From 28baed18c0a56fd2b7f3085da12cdef0db7a5365 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Fri, 20 Oct 2017 18:55:41 -0700 Subject: [PATCH 01/33] Added code for OBJBaker and moved Texture and Mesh compression to ModelBaker superclass --- libraries/baking/src/FBXBaker.cpp | 404 +++++++++---------- libraries/baking/src/FBXBaker.h | 12 +- libraries/baking/src/ModelBaker.cpp | 532 +++++++++++++++++++++++++ libraries/baking/src/ModelBaker.h | 68 ++++ libraries/baking/src/OBJBaker.cpp | 533 ++++++++++++++++++++++++++ libraries/baking/src/OBJBaker.h | 63 +++ tools/oven/src/Oven.cpp | 13 + tools/oven/src/ui/ModelBakeWidget.cpp | 90 +++-- tools/oven/src/ui/ModelBakeWidget.h | 8 +- 9 files changed, 1452 insertions(+), 271 deletions(-) create mode 100644 libraries/baking/src/ModelBaker.cpp create mode 100644 libraries/baking/src/ModelBaker.h create mode 100644 libraries/baking/src/OBJBaker.cpp create mode 100644 libraries/baking/src/OBJBaker.h diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index e4d7f6bbc9..e49e015c2d 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -51,8 +51,7 @@ FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGet _fbxURL(fbxURL), _bakedOutputDir(bakedOutputDir), _originalOutputDir(originalOutputDir), - _textureThreadGetter(textureThreadGetter) -{ + _textureThreadGetter(textureThreadGetter) { } @@ -79,7 +78,7 @@ void FBXBaker::abort() { void FBXBaker::bake() { qDebug() << "FBXBaker" << _fbxURL << "bake starting"; - + auto tempDir = PathUtils::generateTemporaryDir(); if (tempDir.isEmpty()) { @@ -162,7 +161,7 @@ void FBXBaker::loadSourceFBX() { // check if the FBX is local or first needs to be downloaded if (_fbxURL.isLocalFile()) { // load up the local file - QFile localFBX { _fbxURL.toLocalFile() }; + QFile localFBX{ _fbxURL.toLocalFile() }; qDebug() << "Local file url: " << _fbxURL << _fbxURL.toString() << _fbxURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; @@ -273,7 +272,7 @@ QString FBXBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { // in case another texture referenced by this model has the same base name auto& nameMatches = _textureNameMatchCount[textureFileInfo.baseName()]; - QString bakedTextureFileName { textureFileInfo.completeBaseName() }; + QString bakedTextureFileName{ textureFileInfo.completeBaseName() }; if (nameMatches > 0) { // there are already nameMatches texture with this name @@ -297,7 +296,7 @@ QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeF if (isEmbedded) { urlToTexture = _fbxURL.toString() + "/" + apparentRelativePath.filePath(); - } else { + } else { if (textureFileInfo.exists() && textureFileInfo.isFile()) { // set the texture URL to the local texture that we have confirmed exists urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); @@ -323,7 +322,7 @@ QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeF void FBXBaker::rewriteAndBakeSceneModels() { unsigned int meshIndex = 0; - bool hasDeformers { false }; + bool hasDeformers{ false }; for (FBXNode& rootChild : _rootNode.children) { if (rootChild.name == "Objects") { for (FBXNode& objectChild : rootChild.children) { @@ -344,178 +343,19 @@ void FBXBaker::rewriteAndBakeSceneModels() { // TODO Pull this out of _geometry instead so we don't have to reprocess it auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); - auto& mesh = extractedMesh.mesh; - if (mesh.wasCompressed) { - handleError("Cannot re-bake a file that contains compressed mesh"); - return; - } - - Q_ASSERT(mesh.normals.size() == 0 || mesh.normals.size() == mesh.vertices.size()); - Q_ASSERT(mesh.colors.size() == 0 || mesh.colors.size() == mesh.vertices.size()); - Q_ASSERT(mesh.texCoords.size() == 0 || mesh.texCoords.size() == mesh.vertices.size()); - - int64_t numTriangles { 0 }; - for (auto& part : mesh.parts) { - if ((part.quadTrianglesIndices.size() % 3) != 0 || (part.triangleIndices.size() % 3) != 0) { - handleWarning("Found a mesh part with invalid index data, skipping"); - continue; - } - numTriangles += part.quadTrianglesIndices.size() / 3; - numTriangles += part.triangleIndices.size() / 3; - } - - if (numTriangles == 0) { + // Callback to get MaterialID from FBXBaker in ModelBaker + getMaterialIDCallback materialIDcallback = [extractedMesh](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + // Compress mesh information and store in dracoMeshNode + FBXNode* dracoMeshNode = this->compressMesh(extractedMesh.mesh, hasDeformers, materialIDcallback); + // if dracoMeshNode is null (i.e error occurred while baking), continue iterating through Object node children + if (!dracoMeshNode) { continue; } - draco::TriangleSoupMeshBuilder meshBuilder; + objectChild.children.push_back(*dracoMeshNode); - meshBuilder.Start(numTriangles); - - bool hasNormals { mesh.normals.size() > 0 }; - bool hasColors { mesh.colors.size() > 0 }; - bool hasTexCoords { mesh.texCoords.size() > 0 }; - bool hasTexCoords1 { mesh.texCoords1.size() > 0 }; - bool hasPerFaceMaterials { mesh.parts.size() > 1 }; - bool needsOriginalIndices { hasDeformers }; - - int normalsAttributeID { -1 }; - int colorsAttributeID { -1 }; - int texCoordsAttributeID { -1 }; - int texCoords1AttributeID { -1 }; - int faceMaterialAttributeID { -1 }; - int originalIndexAttributeID { -1 }; - - const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION, - 3, draco::DT_FLOAT32); - if (needsOriginalIndices) { - originalIndexAttributeID = meshBuilder.AddAttribute( - (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_ORIGINAL_INDEX, - 1, draco::DT_INT32); - } - - if (hasNormals) { - normalsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::NORMAL, - 3, draco::DT_FLOAT32); - } - if (hasColors) { - colorsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::COLOR, - 3, draco::DT_FLOAT32); - } - if (hasTexCoords) { - texCoordsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::TEX_COORD, - 2, draco::DT_FLOAT32); - } - if (hasTexCoords1) { - texCoords1AttributeID = meshBuilder.AddAttribute( - (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_TEX_COORD_1, - 2, draco::DT_FLOAT32); - } - if (hasPerFaceMaterials) { - faceMaterialAttributeID = meshBuilder.AddAttribute( - (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_MATERIAL_ID, - 1, draco::DT_UINT16); - } - - - auto partIndex = 0; - draco::FaceIndex face; - for (auto& part : mesh.parts) { - const auto& matTex = extractedMesh.partMaterialTextures[partIndex]; - uint16_t materialID = matTex.first; - - auto addFace = [&](QVector& indices, int index, draco::FaceIndex face) { - int32_t idx0 = indices[index]; - int32_t idx1 = indices[index + 1]; - int32_t idx2 = indices[index + 2]; - - if (hasPerFaceMaterials) { - meshBuilder.SetPerFaceAttributeValueForFace(faceMaterialAttributeID, face, &materialID); - } - - meshBuilder.SetAttributeValuesForFace(positionAttributeID, face, - &mesh.vertices[idx0], &mesh.vertices[idx1], - &mesh.vertices[idx2]); - - if (needsOriginalIndices) { - meshBuilder.SetAttributeValuesForFace(originalIndexAttributeID, face, - &mesh.originalIndices[idx0], - &mesh.originalIndices[idx1], - &mesh.originalIndices[idx2]); - } - if (hasNormals) { - meshBuilder.SetAttributeValuesForFace(normalsAttributeID, face, - &mesh.normals[idx0], &mesh.normals[idx1], - &mesh.normals[idx2]); - } - if (hasColors) { - meshBuilder.SetAttributeValuesForFace(colorsAttributeID, face, - &mesh.colors[idx0], &mesh.colors[idx1], - &mesh.colors[idx2]); - } - if (hasTexCoords) { - meshBuilder.SetAttributeValuesForFace(texCoordsAttributeID, face, - &mesh.texCoords[idx0], &mesh.texCoords[idx1], - &mesh.texCoords[idx2]); - } - if (hasTexCoords1) { - meshBuilder.SetAttributeValuesForFace(texCoords1AttributeID, face, - &mesh.texCoords1[idx0], &mesh.texCoords1[idx1], - &mesh.texCoords1[idx2]); - } - }; - - for (int i = 0; (i + 2) < part.quadTrianglesIndices.size(); i += 3) { - addFace(part.quadTrianglesIndices, i, face++); - } - - for (int i = 0; (i + 2) < part.triangleIndices.size(); i += 3) { - addFace(part.triangleIndices, i, face++); - } - - partIndex++; - } - - auto dracoMesh = meshBuilder.Finalize(); - - if (!dracoMesh) { - handleWarning("Failed to finalize the baking of a draco Geometry node"); - continue; - } - - // we need to modify unique attribute IDs for custom attributes - // so the attributes are easily retrievable on the other side - if (hasPerFaceMaterials) { - dracoMesh->attribute(faceMaterialAttributeID)->set_unique_id(DRACO_ATTRIBUTE_MATERIAL_ID); - } - - if (hasTexCoords1) { - dracoMesh->attribute(texCoords1AttributeID)->set_unique_id(DRACO_ATTRIBUTE_TEX_COORD_1); - } - - if (needsOriginalIndices) { - dracoMesh->attribute(originalIndexAttributeID)->set_unique_id(DRACO_ATTRIBUTE_ORIGINAL_INDEX); - } - - draco::Encoder encoder; - - encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 14); - encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, 12); - encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 10); - encoder.SetSpeedOptions(0, 5); - - draco::EncoderBuffer buffer; - encoder.EncodeMeshToBuffer(*dracoMesh, &buffer); - - FBXNode dracoMeshNode; - dracoMeshNode.name = "DracoMesh"; - auto value = QVariant::fromValue(QByteArray(buffer.data(), (int) buffer.size())); - dracoMeshNode.properties.append(value); - - objectChild.children.push_back(dracoMeshNode); - - static const std::vector nodeNamesToDelete { + static const std::vector nodeNamesToDelete{ // Node data that is packed into the draco mesh "Vertices", "PolygonVertexIndex", @@ -548,6 +388,7 @@ void FBXBaker::rewriteAndBakeSceneModels() { } } + void FBXBaker::rewriteAndBakeSceneTextures() { using namespace image::TextureUsage; QHash textureTypes; @@ -591,69 +432,97 @@ void FBXBaker::rewriteAndBakeSceneTextures() { if (textureChild.name == "RelativeFilename") { // use QFileInfo to easily split up the existing texture filename into its components - QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() }; - QFileInfo textureFileInfo { fbxTextureFileName.replace("\\", "/") }; + QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; - if (hasErrors()) { - return; - } + // Callback to get texture content and type from FBXBaker in ModelBaker + //auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); + //qCDebug(model_baking) << "TextureContent" << textureContent.size(); + + getTextureContentTypeCallback textureContentTypeCallback = [=]() { + QPair result; + result.first = _textureContent.value(fbxTextureFileName.toLocal8Bit());; + result.second = textureTypes[object->properties[0].toByteArray()]; + return result; + }; + + // Compress the texture information and return the new filename to be added into the FBX scene + QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); + + // If no errors or warnings have occurred during texture compression add the filename to the FBX scene + if (bakedTextureFile) { + textureChild.properties[0] = *bakedTextureFile; + } else { + if (hasErrors()) { + return; + } else if (hasWarnings()) { + continue; + } + } - if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { - // re-baking an FBX that already references baked textures is a fail - // so we add an error and return from here - handleError("Cannot re-bake a file that references compressed textures"); - return; - } + //QFileInfo textureFileInfo{ fbxTextureFileName.replace("\\", "/") }; - if (!TextureBaker::getSupportedFormats().contains(textureFileInfo.suffix())) { - // this is a texture format we don't bake, skip it - handleWarning(fbxTextureFileName + " is not a bakeable texture format"); - continue; - } + //if (hasErrors()) { + // return; + //} - // make sure this texture points to something and isn't one we've already re-mapped - if (!textureFileInfo.filePath().isEmpty()) { - // check if this was an embedded texture we have already have in-memory content for - auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); + //if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { + // // re-baking an FBX that already references baked textures is a fail + // // so we add an error and return from here + // handleError("Cannot re-bake a file that references compressed textures"); - // figure out the URL to this texture, embedded or external - auto urlToTexture = getTextureURL(textureFileInfo, fbxTextureFileName, - !textureContent.isNull()); + // return; + //} - QString bakedTextureFileName; - if (_remappedTexturePaths.contains(urlToTexture)) { - bakedTextureFileName = _remappedTexturePaths[urlToTexture]; - } else { - // construct the new baked texture file name and file path - // ensuring that the baked texture will have a unique name - // even if there was another texture with the same name at a different path - bakedTextureFileName = createBakedTextureFileName(textureFileInfo); - _remappedTexturePaths[urlToTexture] = bakedTextureFileName; - } + //if (!TextureBaker::getSupportedFormats().contains(textureFileInfo.suffix())) { + // // this is a texture format we don't bake, skip it + // handleWarning(fbxTextureFileName + " is not a bakeable texture format"); + // continue; + //} - qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName - << "to" << bakedTextureFileName; + //// make sure this texture points to something and isn't one we've already re-mapped + //if (!textureFileInfo.filePath().isEmpty()) { + // // check if this was an embedded texture we have already have in-memory content for + // auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - QString bakedTextureFilePath { - _bakedOutputDir + "/" + bakedTextureFileName - }; + // // figure out the URL to this texture, embedded or external + // qCDebug(model_baking) << "TextureContent" << textureContent.size(); + // auto urlToTexture = getTextureURL(textureFileInfo, fbxTextureFileName, + // !textureContent.isNull()); - // write the new filename into the FBX scene - textureChild.properties[0] = bakedTextureFileName.toLocal8Bit(); + // QString bakedTextureFileName; + // if (_remappedTexturePaths.contains(urlToTexture)) { + // bakedTextureFileName = _remappedTexturePaths[urlToTexture]; + // } else { + // // construct the new baked texture file name and file path + // // ensuring that the baked texture will have a unique name + // // even if there was another texture with the same name at a different path + // bakedTextureFileName = createBakedTextureFileName(textureFileInfo); + // _remappedTexturePaths[urlToTexture] = bakedTextureFileName; + // } - if (!_bakingTextures.contains(urlToTexture)) { - _outputFiles.push_back(bakedTextureFilePath); + // qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName + // << "to" << bakedTextureFileName; - // grab the ID for this texture so we can figure out the - // texture type from the loaded materials - QString textureID { object->properties[0].toByteArray() }; - auto textureType = textureTypes[textureID]; + // QString bakedTextureFilePath{ + // _bakedOutputDir + "/" + bakedTextureFileName + // }; - // bake this texture asynchronously - bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); - } - } + // // write the new filename into the FBX scene + // textureChild.properties[0] = bakedTextureFileName.toLocal8Bit(); + + // if (!_bakingTextures.contains(urlToTexture)) { + // _outputFiles.push_back(bakedTextureFilePath); + + // // grab the ID for this texture so we can figure out the + // // texture type from the loaded materials + // QString textureID{ object->properties[0].toByteArray() }; + // auto textureType = textureTypes[textureID]; + + // // bake this texture asynchronously + // bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); + // } + //} } } @@ -670,10 +539,93 @@ void FBXBaker::rewriteAndBakeSceneTextures() { } } +//void FBXBaker::rewriteAndBakeSceneTextures() { +// using namespace image::TextureUsage; +// QHash textureTypes; +// +// // enumerate the materials in the extracted geometry so we can determine the texture type for each texture ID +// for (const auto& material : _geometry->materials) { +// if (material.normalTexture.isBumpmap) { +// textureTypes[material.normalTexture.id] = BUMP_TEXTURE; +// } else { +// textureTypes[material.normalTexture.id] = NORMAL_TEXTURE; +// } +// +// textureTypes[material.albedoTexture.id] = ALBEDO_TEXTURE; +// textureTypes[material.glossTexture.id] = GLOSS_TEXTURE; +// textureTypes[material.roughnessTexture.id] = ROUGHNESS_TEXTURE; +// textureTypes[material.specularTexture.id] = SPECULAR_TEXTURE; +// textureTypes[material.metallicTexture.id] = METALLIC_TEXTURE; +// textureTypes[material.emissiveTexture.id] = EMISSIVE_TEXTURE; +// textureTypes[material.occlusionTexture.id] = OCCLUSION_TEXTURE; +// textureTypes[material.lightmapTexture.id] = LIGHTMAP_TEXTURE; +// } +// +// // enumerate the children of the root node +// for (FBXNode& rootChild : _rootNode.children) { +// +// if (rootChild.name == "Objects") { +// +// // enumerate the objects +// auto object = rootChild.children.begin(); +// while (object != rootChild.children.end()) { +// if (object->name == "Texture") { +// +// // double check that we didn't get an abort while baking the last texture +// if (shouldStop()) { +// return; +// } +// +// // enumerate the texture children +// for (FBXNode& textureChild : object->children) { +// +// if (textureChild.name == "RelativeFilename") { +// QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; +// +// // Callback to get texture content and type from FBXBaker in ModelBaker +// auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); +// qCDebug(model_baking) << "TextureContent" << textureContent; +// +// getTextureContentTypeCallback textureContentTypeCallback = [fbxTextureFileName, textureTypes, object, textureContent]() { +// QPair result; +// result.first = textureContent; +// result.second = textureTypes[object->properties[0].toByteArray()]; +// return result; +// }; +// +// // Compress the texture information and return the new filename to be added into the FBX scene +// QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); +// +// // If no errors or warnings have occurred during texture compression add the filename to the FBX scene +// if (bakedTextureFile) { +// textureChild.properties[0] = *bakedTextureFile; +// } else { +// if (hasErrors()) { +// return; +// } else if (hasWarnings()) { +// continue; +// } +// } +// } +// } +// +// ++object; +// +// } else if (object->name == "Video") { +// // this is an embedded texture, we need to remove it from the FBX +// object = rootChild.children.erase(object); +// } else { +// ++object; +// } +// } +// } +// } +//} + void FBXBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { // start a bake for this texture and add it to our list to keep track of - QSharedPointer bakingTexture { + QSharedPointer bakingTexture{ new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), &TextureBaker::deleteLater }; @@ -713,7 +665,7 @@ void FBXBaker::handleBakedTexture() { // check if we have a relative path to use for the texture auto relativeTexturePath = texturePathRelativeToFBX(_fbxURL, bakedTexture->getTextureURL()); - QFile originalTextureFile { + QFile originalTextureFile{ _originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName() }; diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index a6034ee2b7..dbb7ab823e 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -19,7 +19,7 @@ #include "Baker.h" #include "TextureBaker.h" - +#include "ModelBaker.h" #include "ModelBakingLoggingCategory.h" #include @@ -30,7 +30,7 @@ static const QString BAKED_FBX_EXTENSION = ".baked.fbx"; using TextureBakerThreadGetter = std::function; -class FBXBaker : public Baker { +class FBXBaker : public ModelBaker { Q_OBJECT public: FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, @@ -42,14 +42,14 @@ public: virtual void setWasAborted(bool wasAborted) override; -public slots: + public slots: virtual void bake() override; virtual void abort() override; signals: void sourceCopyReadyToLoad(); -private slots: + private slots: void bakeSourceCopy(); void handleFBXNetworkReply(); void handleBakedTexture(); @@ -79,7 +79,7 @@ private: FBXNode _rootNode; FBXGeometry* _geometry; QHash _textureContent; - + QString _bakedFBXFilePath; QString _bakedOutputDir; @@ -96,7 +96,7 @@ private: TextureBakerThreadGetter _textureThreadGetter; - bool _pendingErrorEmission { false }; + bool _pendingErrorEmission{ false }; }; #endif // hifi_FBXBaker_h diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp new file mode 100644 index 0000000000..1ac27ce570 --- /dev/null +++ b/libraries/baking/src/ModelBaker.cpp @@ -0,0 +1,532 @@ +// +// ModelBaker.cpp +// libraries/baking/src +// +// Created by Utkarsh Gautam on 9/29/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ModelBaker.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include "ModelBakingLoggingCategory.h" +#include "TextureBaker.h" + +#include "FBXBaker.h" + +#ifdef _WIN32 +#pragma warning( push ) +#pragma warning( disable : 4267 ) +#endif + +#include +#include + +#ifdef _WIN32 +#pragma warning( pop ) +#endif + +ModelBaker::ModelBaker() {} + +void ModelBaker::bake() {} + +//void ModelBaker::abort() { +// Baker::abort(); +// +// // tell our underlying TextureBaker instances to abort +// // the FBXBaker will wait until all are aborted before emitting its own abort signal +// for (auto& textureBaker : _bakingTextures) { +// textureBaker->abort(); +// } +//} + +FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback) { + if (mesh.wasCompressed) { + handleError("Cannot re-bake a file that contains compressed mesh"); + return nullptr; + } + + Q_ASSERT(mesh.normals.size() == 0 || mesh.normals.size() == mesh.vertices.size()); + Q_ASSERT(mesh.colors.size() == 0 || mesh.colors.size() == mesh.vertices.size()); + Q_ASSERT(mesh.texCoords.size() == 0 || mesh.texCoords.size() == mesh.vertices.size()); + + int64_t numTriangles{ 0 }; + for (auto& part : mesh.parts) { + if ((part.quadTrianglesIndices.size() % 3) != 0 || (part.triangleIndices.size() % 3) != 0) { + handleWarning("Found a mesh part with invalid index data, skipping"); + continue; + } + numTriangles += part.quadTrianglesIndices.size() / 3; + numTriangles += part.triangleIndices.size() / 3; + } + + if (numTriangles == 0) { + return nullptr; + } + + draco::TriangleSoupMeshBuilder meshBuilder; + + meshBuilder.Start(numTriangles); + + bool hasNormals{ mesh.normals.size() > 0 }; + bool hasColors{ mesh.colors.size() > 0 }; + bool hasTexCoords{ mesh.texCoords.size() > 0 }; + bool hasTexCoords1{ mesh.texCoords1.size() > 0 }; + bool hasPerFaceMaterials; + if (materialIDCallback) { + if (mesh.parts.size() > 1 || materialIDCallback(0) != 0) { + hasPerFaceMaterials = true; + } + } else { + hasPerFaceMaterials = true; + } + + bool needsOriginalIndices{ hasDeformers }; + + int normalsAttributeID{ -1 }; + int colorsAttributeID{ -1 }; + int texCoordsAttributeID{ -1 }; + int texCoords1AttributeID{ -1 }; + int faceMaterialAttributeID{ -1 }; + int originalIndexAttributeID{ -1 }; + + const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION, + 3, draco::DT_FLOAT32); + if (needsOriginalIndices) { + originalIndexAttributeID = meshBuilder.AddAttribute( + (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_ORIGINAL_INDEX, + 1, draco::DT_INT32); + } + + if (hasNormals) { + normalsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::NORMAL, + 3, draco::DT_FLOAT32); + } + if (hasColors) { + colorsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::COLOR, + 3, draco::DT_FLOAT32); + } + if (hasTexCoords) { + texCoordsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::TEX_COORD, + 2, draco::DT_FLOAT32); + } + if (hasTexCoords1) { + texCoords1AttributeID = meshBuilder.AddAttribute( + (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_TEX_COORD_1, + 2, draco::DT_FLOAT32); + } + if (hasPerFaceMaterials) { + faceMaterialAttributeID = meshBuilder.AddAttribute( + (draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_MATERIAL_ID, + 1, draco::DT_UINT16); + } + + + auto partIndex = 0; + draco::FaceIndex face; + uint16_t materialID; + + for (auto& part : mesh.parts) { + if (materialIDCallback) { + materialID = materialIDCallback(partIndex); + } else { + materialID = partIndex; + } + + auto addFace = [&](QVector& indices, int index, draco::FaceIndex face) { + int32_t idx0 = indices[index]; + int32_t idx1 = indices[index + 1]; + int32_t idx2 = indices[index + 2]; + + if (hasPerFaceMaterials) { + meshBuilder.SetPerFaceAttributeValueForFace(faceMaterialAttributeID, face, &materialID); + } + + meshBuilder.SetAttributeValuesForFace(positionAttributeID, face, + &mesh.vertices[idx0], &mesh.vertices[idx1], + &mesh.vertices[idx2]); + + if (needsOriginalIndices) { + meshBuilder.SetAttributeValuesForFace(originalIndexAttributeID, face, + &mesh.originalIndices[idx0], + &mesh.originalIndices[idx1], + &mesh.originalIndices[idx2]); + } + if (hasNormals) { + meshBuilder.SetAttributeValuesForFace(normalsAttributeID, face, + &mesh.normals[idx0], &mesh.normals[idx1], + &mesh.normals[idx2]); + } + if (hasColors) { + meshBuilder.SetAttributeValuesForFace(colorsAttributeID, face, + &mesh.colors[idx0], &mesh.colors[idx1], + &mesh.colors[idx2]); + } + if (hasTexCoords) { + meshBuilder.SetAttributeValuesForFace(texCoordsAttributeID, face, + &mesh.texCoords[idx0], &mesh.texCoords[idx1], + &mesh.texCoords[idx2]); + } + if (hasTexCoords1) { + meshBuilder.SetAttributeValuesForFace(texCoords1AttributeID, face, + &mesh.texCoords1[idx0], &mesh.texCoords1[idx1], + &mesh.texCoords1[idx2]); + } + }; + + for (int i = 0; (i + 2) < part.quadTrianglesIndices.size(); i += 3) { + addFace(part.quadTrianglesIndices, i, face++); + } + + for (int i = 0; (i + 2) < part.triangleIndices.size(); i += 3) { + addFace(part.triangleIndices, i, face++); + } + + partIndex++; + } + + auto dracoMesh = meshBuilder.Finalize(); + + if (!dracoMesh) { + handleWarning("Failed to finalize the baking of a draco Geometry node"); + return nullptr; + } + + // we need to modify unique attribute IDs for custom attributes + // so the attributes are easily retrievable on the other side + if (hasPerFaceMaterials) { + dracoMesh->attribute(faceMaterialAttributeID)->set_unique_id(DRACO_ATTRIBUTE_MATERIAL_ID); + } + + if (hasTexCoords1) { + dracoMesh->attribute(texCoords1AttributeID)->set_unique_id(DRACO_ATTRIBUTE_TEX_COORD_1); + } + + if (needsOriginalIndices) { + dracoMesh->attribute(originalIndexAttributeID)->set_unique_id(DRACO_ATTRIBUTE_ORIGINAL_INDEX); + } + + draco::Encoder encoder; + + encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 14); + encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, 12); + encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 10); + encoder.SetSpeedOptions(0, 5); + + draco::EncoderBuffer buffer; + encoder.EncodeMeshToBuffer(*dracoMesh, &buffer); + + static FBXNode dracoMeshNode; + dracoMeshNode.name = "DracoMesh"; + auto value = QVariant::fromValue(QByteArray(buffer.data(), (int)buffer.size())); + dracoMeshNode.properties.append(value); + + return &dracoMeshNode; +} + +QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl modelURL, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, + getTextureContentTypeCallback textureContentTypeCallback, const QString& originalOutputDir) { + _modelURL = modelURL; + _textureThreadGetter = textureThreadGetter; + _originalOutputDir = originalOutputDir; + + static QByteArray textureChild; + + QPair textureContentType; + // grab the ID for this texture so we can figure out the + // texture type from the loaded materials + textureContentType = textureContentTypeCallback(); + + QByteArray textureContent = textureContentType.first; + image::TextureUsage::Type textureType = textureContentType.second; + + QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; + + if (modelTextureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { + // re-baking a model that already references baked textures + // this is an error - return from here + handleError("Cannot re-bake a file that already references compressed textures"); + return nullptr; + } + + if (!TextureBaker::getSupportedFormats().contains(modelTextureFileInfo.suffix())) { + // this is a texture format we don't bake, skip it + handleWarning(modelTextureFileName + " is not a bakeable texture format"); + return nullptr; + } + + // make sure this texture points to something and isn't one we've already re-mapped + if (!modelTextureFileInfo.filePath().isEmpty()) { + // check if this was an embedded texture that we already have in-memory content for + + // figure out the URL to this texture, embedded or external + //qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); + auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, + true); + + QString bakedTextureFileName; + if (_remappedTexturePaths.contains(urlToTexture)) { + bakedTextureFileName = _remappedTexturePaths[urlToTexture]; + } else { + // construct the new baked texture file name and file path + // ensuring that the baked texture will have a unique name + // even if there was another texture with the same name at a different path + bakedTextureFileName = createBakedTextureFileName(modelTextureFileInfo); + _remappedTexturePaths[urlToTexture] = bakedTextureFileName; + } + + qCDebug(model_baking).noquote() << "Re-mapping" << modelTextureFileName + << "to" << bakedTextureFileName; + + QString bakedTextureFilePath{ + bakedOutputDir + "/" + bakedTextureFileName + }; + + // write the new filename into the FBX scene + textureChild = bakedTextureFileName.toLocal8Bit(); + + if (!_bakingTextures.contains(urlToTexture)) { + _outputFiles.push_back(bakedTextureFilePath); + + // bake this texture asynchronously + qCDebug(model_baking) << "URLHere" << urlToTexture; + bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent); + } + } + + return &textureChild; +} + +QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded) { + QUrl urlToTexture; + + // use QFileInfo to easily split up the existing texture filename into its components + auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/")); + + if (isEmbedded) { + urlToTexture = _modelURL.toString() + "/" + apparentRelativePath.filePath(); + } else { + if (textureFileInfo.exists() && textureFileInfo.isFile()) { + // set the texture URL to the local texture that we have confirmed exists + urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); + } else { + // external texture that we'll need to download or find + + // this is a relative file path which will require different handling + // depending on the location of the original FBX + if (_modelURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) { + // the absolute path we ran into for the texture in the FBX 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 FBX to match the behaviour of interface + urlToTexture = _modelURL.resolved(apparentRelativePath.fileName()); + } + } + } + + return urlToTexture; +} + +void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, + const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { + + // start a bake for this texture and add it to our list to keep track of + QSharedPointer bakingTexture{ + new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), + &TextureBaker::deleteLater + }; + + // make sure we hear when the baking texture is done or aborted + connect(bakingTexture.data(), &Baker::finished, this, &ModelBaker::handleBakedTexture); + connect(bakingTexture.data(), &TextureBaker::aborted, this, &ModelBaker::handleAbortedTexture); + + // keep a shared pointer to the baking texture + _bakingTextures.insert(textureURL, bakingTexture); + + // start baking the texture on one of our available worker threads + bakingTexture->moveToThread(_textureThreadGetter()); + QMetaObject::invokeMethod(bakingTexture.data(), "bake"); +} + +void ModelBaker::handleBakedTexture() { + TextureBaker* bakedTexture = qobject_cast(sender()); + + // make sure we haven't already run into errors, and that this is a valid texture + if (bakedTexture) { + if (!shouldStop()) { + if (!bakedTexture->hasErrors()) { + 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 + + // it is embeddded if the texure being baked was inside a folder with the name of the FBX + // since that is the fake URL we provide when baking external textures + + if (!_modelURL.isParentOf(bakedTexture->getTextureURL())) { + // for linked textures we want to save a copy of original texture beside the original FBX + + 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()); + + QFile originalTextureFile{ + _originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName() + }; + + if (relativeTexturePath.length() > 0) { + // make the folders needed by the relative path + } + + if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) { + qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName() + << "for" << _modelURL; + } else { + handleError("Could not save original external texture " + originalTextureFile.fileName() + + " for " + _modelURL.toString()); + return; + } + } + } + + + // now that this texture has been baked and handled, we can remove that TextureBaker from our hash + _bakingTextures.remove(bakedTexture->getTextureURL()); + + checkIfTexturesFinished(); + } else { + // there was an error baking this texture - add it to our list of errors + _errorList.append(bakedTexture->getErrors()); + + // we don't emit finished yet so that the other textures can finish baking first + _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()); + + // abort any other ongoing texture bakes since we know we'll end up failing + for (auto& bakingTexture : _bakingTextures) { + bakingTexture->abort(); + } + + checkIfTexturesFinished(); + } + } else { + // 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()); + + checkIfTexturesFinished(); + } + } +} + +QString ModelBaker::texturePathRelativeToModel(QUrl fbxURL, QUrl textureURL) { + auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); + auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); + + if (texturePath.startsWith(fbxPath)) { + // texture path is a child of the FBX path, return the texture path without the fbx path + return texturePath.mid(fbxPath.length()); + } else { + // the texture path was not a child of the FBX path, return the empty string + return ""; + } +} + +void ModelBaker::checkIfTexturesFinished() { + // check if we're done everything we need to do for this FBX + // and emit our finished signal if we're done + + 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 + + if (_pendingErrorEmission) { + setIsFinished(true); + } + + return; + } else { + qCDebug(model_baking) << "Finished baking, emitting finished" << _modelURL; + + setIsFinished(true); + } + } +} + +void ModelBaker::handleAbortedTexture() { + // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore + TextureBaker* bakedTexture = qobject_cast(sender()); + + if (bakedTexture) { + _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) { + bakingTexture->abort(); + } + + checkIfTexturesFinished(); +} + +QString ModelBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { + // first make sure we have a unique base name for this texture + // in case another texture referenced by this model has the same base name + auto& nameMatches = _textureNameMatchCount[textureFileInfo.baseName()]; + + QString bakedTextureFileName{ textureFileInfo.completeBaseName() }; + + if (nameMatches > 0) { + // there are already nameMatches texture with this name + // append - and that number to our baked texture file name so that it is unique + bakedTextureFileName += "-" + QString::number(nameMatches); + } + + bakedTextureFileName += BAKED_TEXTURE_EXT; + + // increment the number of name matches + ++nameMatches; + + return bakedTextureFileName; +} + +void ModelBaker::setWasAborted(bool wasAborted) { + if (wasAborted != _wasAborted.load()) { + Baker::setWasAborted(wasAborted); + + if (wasAborted) { + qCDebug(model_baking) << "Aborted baking" << _modelURL; + } + } +} diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h new file mode 100644 index 0000000000..efe6dff874 --- /dev/null +++ b/libraries/baking/src/ModelBaker.h @@ -0,0 +1,68 @@ +// +// ModelBaker.h +// libraries/baking/src +// +// Created by Utkarsh Gautam on 9/29/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ModelBaker_h +#define hifi_ModelBaker_h + +#include +#include +#include +#include + +#include "Baker.h" +#include "TextureBaker.h" + +#include "ModelBakingLoggingCategory.h" + +#include + +#include + +using TextureBakerThreadGetter = std::function; +using getMaterialIDCallback = std::function ; +using getTextureContentTypeCallback = std::function()>; + +class ModelBaker : public Baker{ + Q_OBJECT + +public: + ModelBaker(); + FBXNode* compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback = NULL); + QByteArray* compressTexture(QString textureFileName, QUrl modelUrl, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, + getTextureContentTypeCallback textureContentTypeCallback = NULL, const QString& originalOutputDir = ""); + virtual void setWasAborted(bool wasAborted) override; + +public slots: + virtual void bake() override; + //virtual void abort() override; + +private slots: + void handleBakedTexture(); + void handleAbortedTexture(); + +private: + QString createBakedTextureFileName(const QFileInfo & textureFileInfo); + QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); + void bakeTexture(const QUrl & textureURL, image::TextureUsage::Type textureType, const QDir & outputDir, + const QString & bakedFilename, const QByteArray & textureContent); + QString texturePathRelativeToModel(QUrl fbxURL, QUrl textureURL); + void checkIfTexturesFinished(); + + QHash _textureNameMatchCount; + QHash _remappedTexturePaths; + QUrl _modelURL; + QMultiHash> _bakingTextures; + TextureBakerThreadGetter _textureThreadGetter; + QString _originalOutputDir; + bool _pendingErrorEmission{ false }; +}; + +#endif // hifi_ModelBaker_h diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp new file mode 100644 index 0000000000..a0eed5c5a8 --- /dev/null +++ b/libraries/baking/src/OBJBaker.cpp @@ -0,0 +1,533 @@ +// +// OBJBaker.cpp +// libraries/baking/src +// +// Created by Utkarsh Gautam on 9/29/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include + +#include "OBJBaker.h" +#include "OBJReader.h" +#include "FBXWriter.h" + +OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, + const QString& bakedOutputDir, const QString& originalOutputDir) : + _objURL(objURL), + _bakedOutputDir(bakedOutputDir), + _originalOutputDir(originalOutputDir), + _textureThreadGetter(textureThreadGetter) +{ + +} + +OBJBaker::~OBJBaker() { + if (_tempDir.exists()) { + if (!_tempDir.remove(_originalOBJFilePath)) { + qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalOBJFilePath; + } + if (!_tempDir.rmdir(".")) { + qCWarning(model_baking) << "Failed to remove temporary directory:" << _tempDir; + } + } +} + +void OBJBaker::bake() { + qDebug() << "OBJBaker" << _objURL << "bake starting"; + + auto tempDir = PathUtils::generateTemporaryDir(); + + if (tempDir.isEmpty()) { + handleError("Failed to create a temporary directory."); + return; + } + + _tempDir = tempDir; + + _originalOBJFilePath = _tempDir.filePath(_objURL.fileName()); + qDebug() << "Made temporary dir " << _tempDir; + qDebug() << "Origin file path: " << _originalOBJFilePath; + + // trigger startBake once OBJ is loaded + connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::startBake); + + // make a local copy of the OBJ + loadOBJ(); +} + +void OBJBaker::loadOBJ() { + // check if the OBJ is local or it needs to be downloaded + if (_objURL.isLocalFile()) { + // loading the local OBJ + QFile localOBJ{ _objURL.toLocalFile() }; + + qDebug() << "Local file url: " << _objURL << _objURL.toString() << _objURL.toLocalFile() << ", copying to: " << _originalOBJFilePath; + + if (!localOBJ.exists()) { + handleError("Could not find " + _objURL.toString()); + return; + } + + // make a copy in the output folder + if (!_originalOutputDir.isEmpty()) { + qDebug() << "Copying to: " << _originalOutputDir << "/" << _objURL.fileName(); + localOBJ.copy(_originalOutputDir + "/" + _objURL.fileName()); + } + + localOBJ.copy(_originalOBJFilePath); + + // local OBJ is loaded emit signal to trigger its baking + emit OBJLoaded(); + } else { + // OBJ is remote, start download + auto& networkAccessManager = NetworkAccessManager::getInstance(); + + QNetworkRequest networkRequest; + + // setup the request to follow re-directs and always hit the network + networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setUrl(_objURL); + + qCDebug(model_baking) << "Downloading" << _objURL; + auto networkReply = networkAccessManager.get(networkRequest); + + connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply); + } +} + +void OBJBaker::handleOBJNetworkReply() { + auto requestReply = qobject_cast(sender()); + + if (requestReply->error() == QNetworkReply::NoError) { + qCDebug(model_baking) << "Downloaded" << _objURL; + + // grab the contents of the reply and make a copy in the output folder + QFile copyOfOriginal(_originalOBJFilePath); + + qDebug(model_baking) << "Writing copy of original obj to" << _originalOBJFilePath << 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 " + _objURL.toString() + " (Failed to open " + _originalOBJFilePath + ")"); + return; + } + if (copyOfOriginal.write(requestReply->readAll()) == -1) { + handleError("Could not create copy of " + _objURL.toString() + " (Failed to write)"); + return; + } + + // close that file now that we are done writing to it + copyOfOriginal.close(); + + if (!_originalOutputDir.isEmpty()) { + copyOfOriginal.copy(_originalOutputDir + "/" + _objURL.fileName()); + } + + // emit our signal to start the import of the obj source copy + emit OBJLoaded(); + } else { + // add an error to our list stating that the obj could not be downloaded + handleError("Failed to download " + _objURL.toString()); + } +} + + +void OBJBaker::startBake() { + // Read the OBJ + QFile objFile(_originalOBJFilePath); + if (!objFile.open(QIODevice::ReadOnly)) { + handleError("Error opening " + _originalOBJFilePath + " for reading"); + return; + } + + QByteArray objData = objFile.readAll(); + + bool combineParts = true; + OBJReader reader; + FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _objURL); + + // Write OBJ Data in FBX tree nodes + FBXNode objRoot; + createFBXNodeTree(&objRoot, geometry); + + // Serialize the resultant FBX tree + auto encodedFBX = FBXWriter::encodeFBX(objRoot); + + // Export as baked FBX + auto fileName = _objURL.fileName(); + auto baseName = fileName.left(fileName.lastIndexOf('.')); + auto bakedFilename = baseName + ".baked.fbx"; + + _bakedOBJFilePath = _bakedOutputDir + "/" + bakedFilename; + + QFile bakedFile; + bakedFile.setFileName(_bakedOBJFilePath); + if (!bakedFile.open(QIODevice::WriteOnly)) { + handleError("Error opening " + _bakedOBJFilePath + " for writing"); + return; + } + + bakedFile.write(encodedFBX); + + // Export successful + _outputFiles.push_back(_bakedOBJFilePath); + qCDebug(model_baking) << "Exported" << _objURL << "to" << _bakedOBJFilePath; + // Export done emit finished + emit finished(); +} + +void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { + // Generating FBX Header Node + FBXNode headerNode; + headerNode.name = "FBXHeaderExtension"; + + // Generating global settings node + // Required for Unit Scale Factor + FBXNode globalSettingsNode; + globalSettingsNode.name = "GlobalSettings"; + FBXNode properties70Node; + properties70Node.name = "Properties70"; + FBXNode pNode; + pNode.name = "P"; + setProperties(&pNode); + properties70Node.children = { pNode }; + globalSettingsNode.children = { properties70Node }; + + // Generating Object node + _objectNode.name = "Objects"; + + // Generating Object node's child - Geometry node + FBXNode geometryNode; + geometryNode.name = "Geometry"; + setProperties(&geometryNode); + + // Compress the mesh information and store in dracoNode + bool hasDeformers = false; + ModelBaker modelBaker; + FBXNode* dracoNode = this->compressMesh(geometry->meshes[0], hasDeformers); + geometryNode.children.append(*dracoNode); + + // Generating Object node's child - Model node + FBXNode modelNode; + modelNode.name = "Model"; + setProperties(&modelNode); + _objectNode.children = { geometryNode, modelNode }; + + // Generating Objects node's child - Material node + QVector meshParts = geometry->meshes[0].parts; + for (auto p : meshParts) { + FBXNode materialNode; + materialNode.name = "Material"; + if (geometry->materials.size() == 1) { + foreach(QString materialID, geometry->materials.keys()) { + setMaterialNodeProperties(&materialNode, materialID, geometry); + } + } else { + setMaterialNodeProperties(&materialNode, p.materialID, geometry); + } + _objectNode.children.append(materialNode); + } + + // Texture Node + int count = 0; + 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(_textureID, i)); + QVariant property0(_nodeID++); + FBXNode textureNode; + textureNode.name = "Texture"; + textureNode.properties = { property0 }; + + FBXNode textureNameNode; + textureNameNode.name = "TextureName"; + QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; + auto prop0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + textureNameNode.properties = { prop0 }; + + FBXNode relativeFilenameNode; + relativeFilenameNode.name = "RelativeFilename"; + QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; + getTextureContentTypeCallback textureContentTypeCallback = [=]() { + QPair result; + result.first = NULL; + result.second = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE; + return result; + }; + QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback,_originalOutputDir); + QVariant textureProperty0; + textureProperty0 = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); + relativeFilenameNode.properties = { textureProperty0 }; + + FBXNode properties70Node; + properties70Node.name = "Properties70"; + + QVariant texProperty0; + QVariant texProperty1; + QVariant texProperty2; + QVariant texProperty3; + QVariant texProperty4; + + double value; + + // Set UseMaterial + FBXNode pUseMaterial; + pUseMaterial.name = "P"; + propertyString = "UseMaterial"; + texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "bool"; + texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + int texVal = 1; + texProperty4 = texVal; + + pUseMaterial.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; + + FBXNode pUVSet; + pUVSet.name = "P"; + propertyString = "UVSet"; + texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "KString"; + texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty4 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + pUVSet.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; + + FBXNode pUseMipMap; + pUseMipMap.name = "P"; + propertyString = "UseMipMap"; + texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "bool"; + texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + texVal = 1; + texProperty4 = texVal; + + pUseMipMap.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; + + properties70Node.children = { pUVSet, pUseMaterial, pUseMipMap }; + + textureNode.children = { textureNameNode,relativeFilenameNode, properties70Node }; + + _objectNode.children.append(textureNode); + } + } + + // Generating Connections node + FBXNode connectionsNode; + connectionsNode.name = "Connections"; + // connect Geometry -> Model + FBXNode cNode1; + cNode1.name = "C"; + QByteArray propertyString("OO"); + QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + qlonglong childID = _geometryID; + QVariant property1(childID); + qlonglong parentID = _modelID; + QVariant property2(parentID); + cNode1.properties = { property0, property1, property2 }; + connectionsNode.children = { cNode1}; + + // connect materials to model + for (int i = 0;i < geometry->materials.size();i++) { + FBXNode cNode; + cNode.name = "C"; + property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + property1 = _materialIDs[i]; + property2 = _modelID; + cNode.properties = { property0, property1, property2 }; + connectionsNode.children.append(cNode); + } + + // Texture to material + for (int i = 0;i < mapTextureMaterial.size();i++) { + FBXNode cNode2; + cNode2.name = "C"; + QByteArray propertyString1("OP"); + property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + property1 = mapTextureMaterial[i].first; + int matID = mapTextureMaterial[i].second; + property2 = _materialIDs[matID]; + propertyString1 = "AmbientFactor"; + QVariant connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + cNode2.properties = { property0, property1, property2, connectionProperty }; + connectionsNode.children.append(cNode2); + + FBXNode cNode4; + cNode4.name = "C"; + propertyString1 = "OP"; + property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + property1 = mapTextureMaterial[i].first; + property2 = _materialIDs[matID]; + propertyString1 = "DiffuseColor"; + connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + cNode4.properties = { property0, property1, property2, connectionProperty }; + connectionsNode.children.append(cNode4); + } + + + // Connect all generated nodes to rootNode + objRoot->children = { globalSettingsNode, _objectNode, connectionsNode }; +} + +void OBJBaker::setProperties(FBXNode* parentNode) { + if (parentNode->name == "P") { + QByteArray propertyString("UnitScaleFactor"); + QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "double"; + QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Number"; + QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + QVariant property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + double unitScaleFactor = 100; + QVariant property4(unitScaleFactor); + + parentNode->properties = { property0, property1, property2, property3, property4 }; + } else if (parentNode->name == "Geometry") { + _geometryID = _nodeID; + QVariant property0(_nodeID++); + QByteArray propertyString("Geometry"); + QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Mesh"; + QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + parentNode->properties = { property0, property1, property2 }; + } else if (parentNode->name == "Model") { + _modelID = _nodeID; + QVariant property0(_nodeID++); + QByteArray propertyString("Model"); + QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Mesh"; + QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + parentNode->properties = { property0, property1, property2 }; + } +} + +void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry) { + // Set materialNode properties + _materialIDs.push_back(_nodeID); + QVariant property0(_nodeID++); + QByteArray propertyString(material.toLatin1()); + QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Mesh"; + QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + + materialNode->properties = { property0, property1, property2 }; + + FBXMaterial currentMaterial = geometry->materials[material]; + + FBXNode properties70Node; + properties70Node.name = "Properties70"; + + QVariant materialProperty0; + QVariant materialProperty1; + QVariant materialProperty2; + QVariant materialProperty3; + QVariant materialProperty4; + QVariant materialProperty5; + QVariant materialProperty6; + + double value; + + // Set diffuseColor + FBXNode pNodeDiffuseColor; + pNodeDiffuseColor.name = "P"; + propertyString = "DiffuseColor"; + materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Color"; + materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "A"; + materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + value = (double)currentMaterial.diffuseColor[0]; + materialProperty4 = value; + value = (double)currentMaterial.diffuseColor[1]; + materialProperty5 = value; + value = (double)currentMaterial.diffuseColor[2]; + materialProperty6 = value; + + pNodeDiffuseColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + properties70Node.children.append(pNodeDiffuseColor); + + // Set specularColor + FBXNode pNodeSpecularColor; + pNodeSpecularColor.name = "P"; + propertyString = "SpecularColor"; + materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Color"; + materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "A"; + materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + value = (double)currentMaterial.specularColor[0]; + materialProperty4 = value; + value = (double)currentMaterial.specularColor[1]; + materialProperty5 = value; + value = (double)currentMaterial.specularColor[2]; + materialProperty6 = value; + + pNodeSpecularColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + properties70Node.children.append(pNodeSpecularColor); + + // Set Shininess + FBXNode pNodeShininess; + pNodeShininess.name = "P"; + propertyString = "Shininess"; + materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Number"; + materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "A"; + materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + value = (double)currentMaterial.shininess; + materialProperty4 = value; + + pNodeShininess.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + properties70Node.children.append(pNodeShininess); + + // Set Opacity + FBXNode pNodeOpacity; + pNodeOpacity.name = "P"; + propertyString = "Opacity"; + materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "Number"; + materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = ""; + materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + propertyString = "A"; + materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + value = (double)currentMaterial.opacity; + materialProperty4 = value; + + pNodeOpacity.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + properties70Node.children.append(pNodeOpacity); + + materialNode->children.append(properties70Node); +} diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h new file mode 100644 index 0000000000..2d894c6626 --- /dev/null +++ b/libraries/baking/src/OBJBaker.h @@ -0,0 +1,63 @@ +// +// OBJBaker.h +// libraries/baking/src +// +// Created by Utkarsh Gautam on 9/29/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OBJBaker_h +#define hifi_OBJBaker_h + +#include "Baker.h" +#include "TextureBaker.h" +#include "ModelBaker.h" + +#include "ModelBakingLoggingCategory.h" + +using TextureBakerThreadGetter = std::function; + +class OBJBaker : public ModelBaker { + Q_OBJECT + +public: + OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, + const QString& bakedOutputDir, const QString& originalOutputDir = ""); + ~OBJBaker() override; + void loadOBJ(); + void createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry); + void setProperties(FBXNode * parentNode); + void setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry); + +public slots: + virtual void bake() override; + +signals: + void OBJLoaded(); + +private slots: + void startBake(); + void handleOBJNetworkReply(); + +private: + qlonglong _nodeID = 0; + QUrl _objURL; + QString _bakedOBJFilePath; + QString _bakedOutputDir; + QString _originalOutputDir; + QDir _tempDir; + QString _originalOBJFilePath; + TextureBakerThreadGetter _textureThreadGetter; + QMultiHash> _bakingTextures; + + qlonglong _geometryID; + qlonglong _modelID; + std::vector _materialIDs; + qlonglong _textureID; + std::vector> mapTextureMaterial; + FBXNode _objectNode; +}; +#endif // hifi_OBJBaker_h diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index d91206a592..764f4518c1 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -20,6 +20,13 @@ #include "Oven.h" #include "BakerCLI.h" +#include +#include +#include +#include +#include + + static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; static const QString CLI_INPUT_PARAMETER = "i"; @@ -31,6 +38,12 @@ Oven::Oven(int argc, char* argv[]) : QCoreApplication::setOrganizationName("High Fidelity"); QCoreApplication::setApplicationName("Oven"); + // Initialize classes from Dependency Manager for OBJ Baker + DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(NodeType::Unassigned, -1); + DependencyManager::set(); + // init the settings interface so we can save and load settings Setting::init(); diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 7963b3f3c4..d733a23d23 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -23,7 +23,7 @@ #include "../Oven.h" #include "OvenMainWindow.h" - +#include "OBJBaker.h" #include "ModelBakeWidget.h" static const auto EXPORT_DIR_SETTING_KEY = "model_export_directory"; @@ -32,8 +32,7 @@ static const auto MODEL_START_DIR_SETTING_KEY = "model_search_directory"; ModelBakeWidget::ModelBakeWidget(QWidget* parent, Qt::WindowFlags flags) : BakeWidget(parent, flags), _exportDirectory(EXPORT_DIR_SETTING_KEY), - _modelStartDirectory(MODEL_START_DIR_SETTING_KEY) -{ + _modelStartDirectory(MODEL_START_DIR_SETTING_KEY) { setupUI(); } @@ -114,7 +113,7 @@ void ModelBakeWidget::chooseFileButtonClicked() { startDir = QDir::homePath(); } - auto selectedFiles = QFileDialog::getOpenFileNames(this, "Choose Model", startDir, "Models (*.fbx)"); + auto selectedFiles = QFileDialog::getOpenFileNames(this, "Choose Model", startDir, "Models (*.fbx *.obj)"); if (!selectedFiles.isEmpty()) { // set the contents of the model file text box to be the path to the selected file @@ -165,7 +164,7 @@ void ModelBakeWidget::bakeButtonClicked() { // split the list from the model line edit to see how many models we need to bake auto fileURLStrings = _modelLineEdit->text().split(','); - foreach (QString fileURLString, fileURLStrings) { + foreach(QString fileURLString, fileURLStrings) { // construct a URL from the path in the model file text box QUrl modelToBakeURL(fileURLString); @@ -201,25 +200,35 @@ void ModelBakeWidget::bakeButtonClicked() { QDir bakedOutputDirectory = outputDirectory.absoluteFilePath("baked"); QDir originalOutputDirectory = outputDirectory.absoluteFilePath("original"); - + bakedOutputDirectory.mkdir("."); originalOutputDirectory.mkdir("."); // everything seems to be in place, kick off a bake for this model now - auto baker = std::unique_ptr { - new FBXBaker(modelToBakeURL, []() -> QThread* { + if (modelToBakeURL.fileName().endsWith(".fbx")) { + _baker = std::unique_ptr{ + new FBXBaker(modelToBakeURL, []() -> QThread* { return qApp->getNextWorkerThread(); - }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) - }; + }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) + }; + _isFBX = true; + } else if (modelToBakeURL.fileName().endsWith(".obj")) { + _baker = std::unique_ptr{ + new OBJBaker(modelToBakeURL, []() -> QThread* { + return qApp->getNextWorkerThread(); + }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) + }; + _isOBJ = true; + } - // move the baker to the FBX baker thread - baker->moveToThread(qApp->getNextWorkerThread()); + // move the baker to the FBX/OBJ baker thread + _baker->moveToThread(qApp->getNextWorkerThread()); // invoke the bake method on the baker thread - QMetaObject::invokeMethod(baker.get(), "bake"); + QMetaObject::invokeMethod(_baker.get(), "bake"); // make sure we hear about the results of this baker when it is done - connect(baker.get(), &FBXBaker::finished, this, &ModelBakeWidget::handleFinishedBaker); + connect(_baker.get(), &Baker::finished, this, &ModelBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); @@ -227,32 +236,37 @@ void ModelBakeWidget::bakeButtonClicked() { // keep a unique_ptr to this baker // and remember the row that represents it in the results table - _bakers.emplace_back(std::move(baker), resultsRow); + _bakers.emplace_back(std::move(_baker), resultsRow); } } void ModelBakeWidget::handleFinishedBaker() { - if (auto baker = qobject_cast(sender())) { - // add the results of this bake to the results window - auto it = std::find_if(_bakers.begin(), _bakers.end(), [baker](const BakerRowPair& value) { - return value.first.get() == baker; - }); - - for (auto& file : baker->getOutputFiles()) { - qDebug() << "Baked file: " << file; - } - - if (it != _bakers.end()) { - auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); - - if (baker->hasErrors()) { - resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); - } else { - resultsWindow->changeStatusForRow(resultRow, "Success"); - } - - _bakers.erase(it); - } + Baker* baker; + if (_isFBX) { + baker = qobject_cast(sender()); + } else if (_isOBJ) { + baker = qobject_cast(sender()); } -} + + // add the results of this bake to the results window + auto it = std::find_if(_bakers.begin(), _bakers.end(), [baker](const BakerRowPair& value) { + return value.first.get() == baker; + }); + + for (auto& file : baker->getOutputFiles()) { + qDebug() << "Baked file: " << file; + } + + if (it != _bakers.end()) { + auto resultRow = it->second; + auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + + if (baker->hasErrors()) { + resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); + } else { + resultsWindow->changeStatusForRow(resultRow, "Success"); + } + + _bakers.erase(it); + } +} \ No newline at end of file diff --git a/tools/oven/src/ui/ModelBakeWidget.h b/tools/oven/src/ui/ModelBakeWidget.h index b42b8725f6..e91e5655c6 100644 --- a/tools/oven/src/ui/ModelBakeWidget.h +++ b/tools/oven/src/ui/ModelBakeWidget.h @@ -17,6 +17,7 @@ #include #include +#include #include "BakeWidget.h" @@ -46,6 +47,11 @@ private: Setting::Handle _exportDirectory; Setting::Handle _modelStartDirectory; + + std::unique_ptr _baker; + + bool _isOBJ = false; + bool _isFBX = false; }; -#endif // hifi_ModelBakeWidget_h +#endif // hifi_ModelBakeWidget_h \ No newline at end of file From 46b46c2f4c6e8882cdf7ae68481f32e409d2eb5b Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Mon, 23 Oct 2017 20:07:24 -0700 Subject: [PATCH 02/33] Fixed issues with FBXBaker and refactoring of OBJBaker --- libraries/baking/src/FBXBaker.cpp | 418 +++----------------------- libraries/baking/src/FBXBaker.h | 12 +- libraries/baking/src/ModelBaker.cpp | 67 ++--- libraries/baking/src/ModelBaker.h | 3 +- libraries/baking/src/OBJBaker.cpp | 210 ++++--------- libraries/baking/src/OBJBaker.h | 6 +- tools/oven/src/ui/ModelBakeWidget.cpp | 2 +- 7 files changed, 122 insertions(+), 596 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index e49e015c2d..b835938812 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -33,19 +33,6 @@ #include "FBXBaker.h" -#ifdef _WIN32 -#pragma warning( push ) -#pragma warning( disable : 4267 ) -#endif - -#include -#include - -#ifdef _WIN32 -#pragma warning( pop ) -#endif - - FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : _fbxURL(fbxURL), @@ -254,72 +241,6 @@ void FBXBaker::importScene() { _textureContent = reader._textureContent; } -QString texturePathRelativeToFBX(QUrl fbxURL, QUrl textureURL) { - auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); - auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); - - if (texturePath.startsWith(fbxPath)) { - // texture path is a child of the FBX path, return the texture path without the fbx path - return texturePath.mid(fbxPath.length()); - } else { - // the texture path was not a child of the FBX path, return the empty string - return ""; - } -} - -QString FBXBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { - // first make sure we have a unique base name for this texture - // in case another texture referenced by this model has the same base name - auto& nameMatches = _textureNameMatchCount[textureFileInfo.baseName()]; - - QString bakedTextureFileName{ textureFileInfo.completeBaseName() }; - - if (nameMatches > 0) { - // there are already nameMatches texture with this name - // append - and that number to our baked texture file name so that it is unique - bakedTextureFileName += "-" + QString::number(nameMatches); - } - - bakedTextureFileName += BAKED_TEXTURE_EXT; - - // increment the number of name matches - ++nameMatches; - - return bakedTextureFileName; -} - -QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded) { - - QUrl urlToTexture; - - auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/")); - - if (isEmbedded) { - urlToTexture = _fbxURL.toString() + "/" + apparentRelativePath.filePath(); - } else { - if (textureFileInfo.exists() && textureFileInfo.isFile()) { - // set the texture URL to the local texture that we have confirmed exists - urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); - } else { - // external texture that we'll need to download or find - - // this is a relative file path which will require different handling - // depending on the location of the original FBX - if (_fbxURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) { - // the absolute path we ran into for the texture in the FBX 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 FBX to match the behaviour of interface - urlToTexture = _fbxURL.resolved(apparentRelativePath.fileName()); - } - } - } - - return urlToTexture; -} - void FBXBaker::rewriteAndBakeSceneModels() { unsigned int meshIndex = 0; bool hasDeformers{ false }; @@ -343,17 +264,21 @@ void FBXBaker::rewriteAndBakeSceneModels() { // TODO Pull this out of _geometry instead so we don't have to reprocess it auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); - + // Callback to get MaterialID from FBXBaker in ModelBaker - getMaterialIDCallback materialIDcallback = [extractedMesh](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + getMaterialIDCallback materialIDcallback = [=](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + // Compress mesh information and store in dracoMeshNode - FBXNode* dracoMeshNode = this->compressMesh(extractedMesh.mesh, hasDeformers, materialIDcallback); - // if dracoMeshNode is null (i.e error occurred while baking), continue iterating through Object node children - if (!dracoMeshNode) { + FBXNode dracoMeshNode; + bool success = this->compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback); + + // if bake fails continue iterating through Object node's children + if (!success) { continue; } - objectChild.children.push_back(*dracoMeshNode); + //objectChild.children.push_back(*dracoMeshNode); + objectChild.children.push_back(dracoMeshNode); static const std::vector nodeNamesToDelete{ // Node data that is packed into the draco mesh @@ -388,7 +313,6 @@ void FBXBaker::rewriteAndBakeSceneModels() { } } - void FBXBaker::rewriteAndBakeSceneTextures() { using namespace image::TextureUsage; QHash textureTypes; @@ -430,99 +354,36 @@ void FBXBaker::rewriteAndBakeSceneTextures() { for (FBXNode& textureChild : object->children) { if (textureChild.name == "RelativeFilename") { - - // use QFileInfo to easily split up the existing texture filename into its components QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; - - // Callback to get texture content and type from FBXBaker in ModelBaker - //auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - //qCDebug(model_baking) << "TextureContent" << textureContent.size(); - - getTextureContentTypeCallback textureContentTypeCallback = [=]() { - QPair result; - result.first = _textureContent.value(fbxTextureFileName.toLocal8Bit());; - result.second = textureTypes[object->properties[0].toByteArray()]; - return result; - }; + QByteArray textureContent = ""; + QFileInfo fbxTextureFileInfo{ fbxTextureFileName.replace("\\", "/") }; + // Callback to get texture content and type from FBXBaker in ModelBaker + if (!fbxTextureFileInfo.filePath().isEmpty()) { + textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); + } - // Compress the texture information and return the new filename to be added into the FBX scene - QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); - - // If no errors or warnings have occurred during texture compression add the filename to the FBX scene - if (bakedTextureFile) { - textureChild.properties[0] = *bakedTextureFile; - } else { - if (hasErrors()) { - return; - } else if (hasWarnings()) { - continue; - } - } + getTextureContentTypeCallback textureContentTypeCallback = [=]() { + QPair result; + result.first = textureContent;// _textureContent.value(fbxTextureFileName.toLocal8Bit()); + auto textureID{ object->properties[0].toByteArray() }; + auto textureType = textureTypes[textureID]; + result.second = textureType; + return result; + }; + // Compress the texture information and return the new filename to be added into the FBX scene + QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); - //QFileInfo textureFileInfo{ fbxTextureFileName.replace("\\", "/") }; - - //if (hasErrors()) { - // return; - //} - - //if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { - // // re-baking an FBX that already references baked textures is a fail - // // so we add an error and return from here - // handleError("Cannot re-bake a file that references compressed textures"); - - // return; - //} - - //if (!TextureBaker::getSupportedFormats().contains(textureFileInfo.suffix())) { - // // this is a texture format we don't bake, skip it - // handleWarning(fbxTextureFileName + " is not a bakeable texture format"); - // continue; - //} - - //// make sure this texture points to something and isn't one we've already re-mapped - //if (!textureFileInfo.filePath().isEmpty()) { - // // check if this was an embedded texture we have already have in-memory content for - // auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - - // // figure out the URL to this texture, embedded or external - // qCDebug(model_baking) << "TextureContent" << textureContent.size(); - // auto urlToTexture = getTextureURL(textureFileInfo, fbxTextureFileName, - // !textureContent.isNull()); - - // QString bakedTextureFileName; - // if (_remappedTexturePaths.contains(urlToTexture)) { - // bakedTextureFileName = _remappedTexturePaths[urlToTexture]; - // } else { - // // construct the new baked texture file name and file path - // // ensuring that the baked texture will have a unique name - // // even if there was another texture with the same name at a different path - // bakedTextureFileName = createBakedTextureFileName(textureFileInfo); - // _remappedTexturePaths[urlToTexture] = bakedTextureFileName; - // } - - // qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName - // << "to" << bakedTextureFileName; - - // QString bakedTextureFilePath{ - // _bakedOutputDir + "/" + bakedTextureFileName - // }; - - // // write the new filename into the FBX scene - // textureChild.properties[0] = bakedTextureFileName.toLocal8Bit(); - - // if (!_bakingTextures.contains(urlToTexture)) { - // _outputFiles.push_back(bakedTextureFilePath); - - // // grab the ID for this texture so we can figure out the - // // texture type from the loaded materials - // QString textureID{ object->properties[0].toByteArray() }; - // auto textureType = textureTypes[textureID]; - - // // bake this texture asynchronously - // bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); - // } - //} + // If no errors or warnings have occurred during texture compression add the filename to the FBX scene + if (bakedTextureFile) { + textureChild.properties[0] = *bakedTextureFile; + } else { + if (hasErrors()) { + return; + } else if (hasWarnings()) { + continue; + } + } } } @@ -539,203 +400,6 @@ void FBXBaker::rewriteAndBakeSceneTextures() { } } -//void FBXBaker::rewriteAndBakeSceneTextures() { -// using namespace image::TextureUsage; -// QHash textureTypes; -// -// // enumerate the materials in the extracted geometry so we can determine the texture type for each texture ID -// for (const auto& material : _geometry->materials) { -// if (material.normalTexture.isBumpmap) { -// textureTypes[material.normalTexture.id] = BUMP_TEXTURE; -// } else { -// textureTypes[material.normalTexture.id] = NORMAL_TEXTURE; -// } -// -// textureTypes[material.albedoTexture.id] = ALBEDO_TEXTURE; -// textureTypes[material.glossTexture.id] = GLOSS_TEXTURE; -// textureTypes[material.roughnessTexture.id] = ROUGHNESS_TEXTURE; -// textureTypes[material.specularTexture.id] = SPECULAR_TEXTURE; -// textureTypes[material.metallicTexture.id] = METALLIC_TEXTURE; -// textureTypes[material.emissiveTexture.id] = EMISSIVE_TEXTURE; -// textureTypes[material.occlusionTexture.id] = OCCLUSION_TEXTURE; -// textureTypes[material.lightmapTexture.id] = LIGHTMAP_TEXTURE; -// } -// -// // enumerate the children of the root node -// for (FBXNode& rootChild : _rootNode.children) { -// -// if (rootChild.name == "Objects") { -// -// // enumerate the objects -// auto object = rootChild.children.begin(); -// while (object != rootChild.children.end()) { -// if (object->name == "Texture") { -// -// // double check that we didn't get an abort while baking the last texture -// if (shouldStop()) { -// return; -// } -// -// // enumerate the texture children -// for (FBXNode& textureChild : object->children) { -// -// if (textureChild.name == "RelativeFilename") { -// QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; -// -// // Callback to get texture content and type from FBXBaker in ModelBaker -// auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); -// qCDebug(model_baking) << "TextureContent" << textureContent; -// -// getTextureContentTypeCallback textureContentTypeCallback = [fbxTextureFileName, textureTypes, object, textureContent]() { -// QPair result; -// result.first = textureContent; -// result.second = textureTypes[object->properties[0].toByteArray()]; -// return result; -// }; -// -// // Compress the texture information and return the new filename to be added into the FBX scene -// QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); -// -// // If no errors or warnings have occurred during texture compression add the filename to the FBX scene -// if (bakedTextureFile) { -// textureChild.properties[0] = *bakedTextureFile; -// } else { -// if (hasErrors()) { -// return; -// } else if (hasWarnings()) { -// continue; -// } -// } -// } -// } -// -// ++object; -// -// } else if (object->name == "Video") { -// // this is an embedded texture, we need to remove it from the FBX -// object = rootChild.children.erase(object); -// } else { -// ++object; -// } -// } -// } -// } -//} - -void FBXBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { - // start a bake for this texture and add it to our list to keep track of - QSharedPointer bakingTexture{ - new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), - &TextureBaker::deleteLater - }; - - // make sure we hear when the baking texture is done or aborted - connect(bakingTexture.data(), &Baker::finished, this, &FBXBaker::handleBakedTexture); - connect(bakingTexture.data(), &TextureBaker::aborted, this, &FBXBaker::handleAbortedTexture); - - // keep a shared pointer to the baking texture - _bakingTextures.insert(textureURL, bakingTexture); - - // start baking the texture on one of our available worker threads - bakingTexture->moveToThread(_textureThreadGetter()); - QMetaObject::invokeMethod(bakingTexture.data(), "bake"); -} - -void FBXBaker::handleBakedTexture() { - TextureBaker* bakedTexture = qobject_cast(sender()); - - // make sure we haven't already run into errors, and that this is a valid texture - if (bakedTexture) { - if (!shouldStop()) { - if (!bakedTexture->hasErrors()) { - 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 - - // it is embeddded if the texure being baked was inside a folder with the name of the FBX - // since that is the fake URL we provide when baking external textures - - if (!_fbxURL.isParentOf(bakedTexture->getTextureURL())) { - // for linked textures we want to save a copy of original texture beside the original FBX - - qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL(); - - // check if we have a relative path to use for the texture - auto relativeTexturePath = texturePathRelativeToFBX(_fbxURL, bakedTexture->getTextureURL()); - - QFile originalTextureFile{ - _originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName() - }; - - if (relativeTexturePath.length() > 0) { - // make the folders needed by the relative path - } - - if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) { - qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName() - << "for" << _fbxURL; - } else { - handleError("Could not save original external texture " + originalTextureFile.fileName() - + " for " + _fbxURL.toString()); - return; - } - } - } - - - // now that this texture has been baked and handled, we can remove that TextureBaker from our hash - _bakingTextures.remove(bakedTexture->getTextureURL()); - - checkIfTexturesFinished(); - } else { - // there was an error baking this texture - add it to our list of errors - _errorList.append(bakedTexture->getErrors()); - - // we don't emit finished yet so that the other textures can finish baking first - _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()); - - // abort any other ongoing texture bakes since we know we'll end up failing - for (auto& bakingTexture : _bakingTextures) { - bakingTexture->abort(); - } - - checkIfTexturesFinished(); - } - } else { - // 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()); - - checkIfTexturesFinished(); - } - } -} - -void FBXBaker::handleAbortedTexture() { - // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore - TextureBaker* bakedTexture = qobject_cast(sender()); - - if (bakedTexture) { - _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) { - bakingTexture->abort(); - } - - checkIfTexturesFinished(); -} - void FBXBaker::exportScene() { // save the relative path to this FBX inside our passed output folder auto fileName = _fbxURL.fileName(); @@ -781,13 +445,3 @@ void FBXBaker::checkIfTexturesFinished() { } } } - -void FBXBaker::setWasAborted(bool wasAborted) { - if (wasAborted != _wasAborted.load()) { - Baker::setWasAborted(wasAborted); - - if (wasAborted) { - qCDebug(model_baking) << "Aborted baking" << _fbxURL; - } - } -} diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index dbb7ab823e..b76d3699b5 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -40,9 +40,7 @@ public: QUrl getFBXUrl() const { return _fbxURL; } QString getBakedFBXFilePath() const { return _bakedFBXFilePath; } - virtual void setWasAborted(bool wasAborted) override; - - public slots: +public slots: virtual void bake() override; virtual void abort() override; @@ -52,8 +50,6 @@ signals: private slots: void bakeSourceCopy(); void handleFBXNetworkReply(); - void handleBakedTexture(); - void handleAbortedTexture(); private: void setupOutputFolder(); @@ -68,12 +64,6 @@ private: void checkIfTexturesFinished(); - QString createBakedTextureFileName(const QFileInfo& textureFileInfo); - QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); - - void bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDir, - const QString& bakedFilename, const QByteArray& textureContent = QByteArray()); - QUrl _fbxURL; FBXNode _rootNode; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 1ac27ce570..0770574035 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -12,29 +12,11 @@ #include "ModelBaker.h" #include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - #include #include #include -#include "ModelBakingLoggingCategory.h" -#include "TextureBaker.h" - -#include "FBXBaker.h" - #ifdef _WIN32 #pragma warning( push ) #pragma warning( disable : 4267 ) @@ -51,20 +33,10 @@ ModelBaker::ModelBaker() {} void ModelBaker::bake() {} -//void ModelBaker::abort() { -// Baker::abort(); -// -// // tell our underlying TextureBaker instances to abort -// // the FBXBaker will wait until all are aborted before emitting its own abort signal -// for (auto& textureBaker : _bakingTextures) { -// textureBaker->abort(); -// } -//} - -FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback) { +bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback) { if (mesh.wasCompressed) { handleError("Cannot re-bake a file that contains compressed mesh"); - return nullptr; + return false; } Q_ASSERT(mesh.normals.size() == 0 || mesh.normals.size() == mesh.vertices.size()); @@ -82,7 +54,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } if (numTriangles == 0) { - return nullptr; + return false; } draco::TriangleSoupMeshBuilder meshBuilder; @@ -93,7 +65,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI bool hasColors{ mesh.colors.size() > 0 }; bool hasTexCoords{ mesh.texCoords.size() > 0 }; bool hasTexCoords1{ mesh.texCoords1.size() > 0 }; - bool hasPerFaceMaterials; + bool hasPerFaceMaterials;// { mesh.parts.size() > 1 }; if (materialIDCallback) { if (mesh.parts.size() > 1 || materialIDCallback(0) != 0) { hasPerFaceMaterials = true; @@ -101,7 +73,6 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } else { hasPerFaceMaterials = true; } - bool needsOriginalIndices{ hasDeformers }; int normalsAttributeID{ -1 }; @@ -153,7 +124,6 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } else { materialID = partIndex; } - auto addFace = [&](QVector& indices, int index, draco::FaceIndex face) { int32_t idx0 = indices[index]; int32_t idx1 = indices[index + 1]; @@ -210,7 +180,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI if (!dracoMesh) { handleWarning("Failed to finalize the baking of a draco Geometry node"); - return nullptr; + return false; } // we need to modify unique attribute IDs for custom attributes @@ -237,12 +207,13 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI draco::EncoderBuffer buffer; encoder.EncodeMeshToBuffer(*dracoMesh, &buffer); - static FBXNode dracoMeshNode; - dracoMeshNode.name = "DracoMesh"; + FBXNode dracoNode; + dracoNode.name = "DracoMesh"; auto value = QVariant::fromValue(QByteArray(buffer.data(), (int)buffer.size())); - dracoMeshNode.properties.append(value); - - return &dracoMeshNode; + dracoNode.properties.append(value); + + dracoMeshNode = dracoNode; + return true; } QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl modelURL, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, @@ -254,12 +225,16 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model static QByteArray textureChild; QPair textureContentType; + QByteArray textureContent; + image::TextureUsage::Type textureType; // grab the ID for this texture so we can figure out the // texture type from the loaded materials - textureContentType = textureContentTypeCallback(); + if (textureContentTypeCallback) { + textureContentType = textureContentTypeCallback(); + textureContent = textureContentType.first; + textureType = textureContentType.second; + } - QByteArray textureContent = textureContentType.first; - image::TextureUsage::Type textureType = textureContentType.second; QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; @@ -281,9 +256,8 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model // check if this was an embedded texture that we already have in-memory content for // figure out the URL to this texture, embedded or external - //qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); - auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, - true); + qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); + auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull()); QString bakedTextureFileName; if (_remappedTexturePaths.contains(urlToTexture)) { @@ -310,7 +284,6 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously - qCDebug(model_baking) << "URLHere" << urlToTexture; bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent); } } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index efe6dff874..e132591120 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -35,14 +35,13 @@ class ModelBaker : public Baker{ public: ModelBaker(); - FBXNode* compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback = NULL); + bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); QByteArray* compressTexture(QString textureFileName, QUrl modelUrl, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, getTextureContentTypeCallback textureContentTypeCallback = NULL, const QString& originalOutputDir = ""); virtual void setWasAborted(bool wasAborted) override; public slots: virtual void bake() override; - //virtual void abort() override; private slots: void handleBakedTexture(); diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index a0eed5c5a8..1f6d820b8c 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -16,6 +16,8 @@ #include "OBJReader.h" #include "FBXWriter.h" +const double UNIT_SCALE_FACTOR = 100; + OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : _objURL(objURL), @@ -149,7 +151,7 @@ void OBJBaker::startBake() { QByteArray objData = objFile.readAll(); - bool combineParts = true; + bool combineParts = true; // set true so that OBJReader reads material info from material library OBJReader reader; FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _objURL); @@ -211,8 +213,9 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Compress the mesh information and store in dracoNode bool hasDeformers = false; ModelBaker modelBaker; - FBXNode* dracoNode = this->compressMesh(geometry->meshes[0], hasDeformers); - geometryNode.children.append(*dracoNode); + FBXNode dracoNode; + this->compressMesh(geometry->meshes[0], hasDeformers, dracoNode); + geometryNode.children.append(dracoNode); // Generating Object node's child - Model node FBXNode modelNode; @@ -222,7 +225,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Generating Objects node's child - Material node QVector meshParts = geometry->meshes[0].parts; - for (auto p : meshParts) { + for (auto meshPart : meshParts) { FBXNode materialNode; materialNode.name = "Material"; if (geometry->materials.size() == 1) { @@ -230,106 +233,52 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { setMaterialNodeProperties(&materialNode, materialID, geometry); } } else { - setMaterialNodeProperties(&materialNode, p.materialID, geometry); + setMaterialNodeProperties(&materialNode, meshPart.materialID, geometry); } _objectNode.children.append(materialNode); } - // Texture Node + // Generating Texture Node int count = 0; + // iterate through mesh parts and process the associated textures 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(_textureID, i)); + _mapTextureMaterial.push_back(QPair(_textureID, i)); QVariant property0(_nodeID++); FBXNode textureNode; textureNode.name = "Texture"; textureNode.properties = { property0 }; - + + // Texture node child - TextureName node FBXNode textureNameNode; textureNameNode.name = "TextureName"; QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; auto prop0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); textureNameNode.properties = { prop0 }; + // Texture node child - Relative Filename node FBXNode relativeFilenameNode; relativeFilenameNode.name = "RelativeFilename"; QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; + + // Callback to get Texture content and type getTextureContentTypeCallback textureContentTypeCallback = [=]() { QPair result; result.first = NULL; result.second = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE; return result; }; + + // Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback,_originalOutputDir); QVariant textureProperty0; textureProperty0 = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); relativeFilenameNode.properties = { textureProperty0 }; - - FBXNode properties70Node; - properties70Node.name = "Properties70"; - - QVariant texProperty0; - QVariant texProperty1; - QVariant texProperty2; - QVariant texProperty3; - QVariant texProperty4; - - double value; - - // Set UseMaterial - FBXNode pUseMaterial; - pUseMaterial.name = "P"; - propertyString = "UseMaterial"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "bool"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - int texVal = 1; - texProperty4 = texVal; - - pUseMaterial.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - FBXNode pUVSet; - pUVSet.name = "P"; - propertyString = "UVSet"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "KString"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty4 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - pUVSet.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - FBXNode pUseMipMap; - pUseMipMap.name = "P"; - propertyString = "UseMipMap"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "bool"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - texVal = 1; - texProperty4 = texVal; - - pUseMipMap.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - properties70Node.children = { pUVSet, pUseMaterial, pUseMipMap }; - - textureNode.children = { textureNameNode,relativeFilenameNode, properties70Node }; + textureNode.children = { textureNameNode,relativeFilenameNode }; _objectNode.children.append(textureNode); } @@ -338,7 +287,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Generating Connections node FBXNode connectionsNode; connectionsNode.name = "Connections"; - // connect Geometry -> Model + // connect Geometry to Model FBXNode cNode1; cNode1.name = "C"; QByteArray propertyString("OO"); @@ -350,7 +299,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { cNode1.properties = { property0, property1, property2 }; connectionsNode.children = { cNode1}; - // connect materials to model + // connect all materials to model for (int i = 0;i < geometry->materials.size();i++) { FBXNode cNode; cNode.name = "C"; @@ -361,14 +310,14 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { connectionsNode.children.append(cNode); } - // Texture to material - for (int i = 0;i < mapTextureMaterial.size();i++) { + // Connect textures to materials + for (int i = 0;i < _mapTextureMaterial.size();i++) { FBXNode cNode2; cNode2.name = "C"; QByteArray propertyString1("OP"); property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - property1 = mapTextureMaterial[i].first; - int matID = mapTextureMaterial[i].second; + property1 = _mapTextureMaterial[i].first; + int matID = _mapTextureMaterial[i].second; property2 = _materialIDs[matID]; propertyString1 = "AmbientFactor"; QVariant connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); @@ -379,7 +328,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { cNode4.name = "C"; propertyString1 = "OP"; property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - property1 = mapTextureMaterial[i].first; + property1 = _mapTextureMaterial[i].first; property2 = _materialIDs[matID]; propertyString1 = "DiffuseColor"; connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); @@ -388,24 +337,16 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { } - // Connect all generated nodes to rootNode + // Make all generated nodes children of rootNode objRoot->children = { globalSettingsNode, _objectNode, connectionsNode }; } void OBJBaker::setProperties(FBXNode* parentNode) { if (parentNode->name == "P") { - QByteArray propertyString("UnitScaleFactor"); - QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "double"; - QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - QVariant property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - double unitScaleFactor = 100; - QVariant property4(unitScaleFactor); + std::vector stringProperties{ "UnitScaleFactor", "double", "Number", "" }; + std::vector numericProperties{ UNIT_SCALE_FACTOR }; - parentNode->properties = { property0, property1, property2, property3, property4 }; + setPropertiesList(stringProperties, numericProperties, parentNode->properties); } else if (parentNode->name == "Geometry") { _geometryID = _nodeID; QVariant property0(_nodeID++); @@ -443,91 +384,58 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material FBXNode properties70Node; properties70Node.name = "Properties70"; - QVariant materialProperty0; - QVariant materialProperty1; - QVariant materialProperty2; - QVariant materialProperty3; - QVariant materialProperty4; - QVariant materialProperty5; - QVariant materialProperty6; - - double value; - // Set diffuseColor FBXNode pNodeDiffuseColor; pNodeDiffuseColor.name = "P"; - propertyString = "DiffuseColor"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Color"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.diffuseColor[0]; - materialProperty4 = value; - value = (double)currentMaterial.diffuseColor[1]; - materialProperty5 = value; - value = (double)currentMaterial.diffuseColor[2]; - materialProperty6 = value; - pNodeDiffuseColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + std::vector stringProperties{ "DiffuseColor", "Color", "", "A" }; + std::vector numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] }; + setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties); + properties70Node.children.append(pNodeDiffuseColor); // Set specularColor FBXNode pNodeSpecularColor; pNodeSpecularColor.name = "P"; - propertyString = "SpecularColor"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Color"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.specularColor[0]; - materialProperty4 = value; - value = (double)currentMaterial.specularColor[1]; - materialProperty5 = value; - value = (double)currentMaterial.specularColor[2]; - materialProperty6 = value; - pNodeSpecularColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + stringProperties = { "SpecularColor", "Color", "", "A" }; + numericProperties = { currentMaterial.specularColor[0], currentMaterial.specularColor[1], currentMaterial.specularColor[2] }; + setPropertiesList(stringProperties, numericProperties, pNodeSpecularColor.properties); + properties70Node.children.append(pNodeSpecularColor); // Set Shininess FBXNode pNodeShininess; pNodeShininess.name = "P"; - propertyString = "Shininess"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.shininess; - materialProperty4 = value; - pNodeShininess.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + stringProperties = { "Shininess", "Number", "", "A" }; + numericProperties = { currentMaterial.shininess }; + setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties); + properties70Node.children.append(pNodeShininess); // Set Opacity FBXNode pNodeOpacity; pNodeOpacity.name = "P"; - propertyString = "Opacity"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.opacity; - materialProperty4 = value; - pNodeOpacity.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + stringProperties = { "Opacity", "Number", "", "A" }; + numericProperties = { currentMaterial.opacity }; + setPropertiesList(stringProperties, numericProperties, pNodeOpacity.properties); + properties70Node.children.append(pNodeOpacity); materialNode->children.append(properties70Node); } + +template +void OBJBaker::setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList) { + foreach(auto stringProperty, stringProperties) { + auto propertyValue = QVariant::fromValue(QByteArray(stringProperty.data(), (int)stringProperty.size())); + propertiesList.append(propertyValue); + } + + foreach(auto numberProperty, numericProperties) { + QVariant propertyValue(numberProperty); + propertiesList.append(propertyValue); + } +} diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 2d894c6626..d331d3bde1 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -31,7 +31,9 @@ public: void createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry); void setProperties(FBXNode * parentNode); void setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry); - + template + void setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList); + public slots: virtual void bake() override; @@ -57,7 +59,7 @@ private: qlonglong _modelID; std::vector _materialIDs; qlonglong _textureID; - std::vector> mapTextureMaterial; + std::vector> _mapTextureMaterial; FBXNode _objectNode; }; #endif // hifi_OBJBaker_h diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index d733a23d23..99727b0df6 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -269,4 +269,4 @@ void ModelBakeWidget::handleFinishedBaker() { _bakers.erase(it); } -} \ No newline at end of file +} From 5d5e62d002fdcc00cf5261cc9a37012c88be8c77 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Tue, 24 Oct 2017 15:44:54 -0700 Subject: [PATCH 03/33] Refactored ModelBaker and OBJBaker --- libraries/baking/src/FBXBaker.cpp | 12 +- libraries/baking/src/ModelBaker.cpp | 47 +++--- libraries/baking/src/ModelBaker.h | 2 +- libraries/baking/src/OBJBaker.cpp | 227 ++++++++++++++++------------ libraries/baking/src/OBJBaker.h | 13 +- 5 files changed, 161 insertions(+), 140 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index b835938812..f91e829c65 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -272,12 +272,15 @@ void FBXBaker::rewriteAndBakeSceneModels() { FBXNode dracoMeshNode; bool success = this->compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback); - // if bake fails continue iterating through Object node's children + // if bake fails - return, if there were errors and continue, if there were warnings. if (!success) { - continue; + if (hasErrors()) { + return; + } else if (hasWarnings()) { + continue; + } } - - //objectChild.children.push_back(*dracoMeshNode); + objectChild.children.push_back(dracoMeshNode); static const std::vector nodeNamesToDelete{ @@ -378,6 +381,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() { if (bakedTextureFile) { textureChild.properties[0] = *bakedTextureFile; } else { + // if bake fails - return, if there were errors and continue, if there were warnings. if (hasErrors()) { return; } else if (hasWarnings()) { diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 0770574035..242d9794ef 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -65,14 +65,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes bool hasColors{ mesh.colors.size() > 0 }; bool hasTexCoords{ mesh.texCoords.size() > 0 }; bool hasTexCoords1{ mesh.texCoords1.size() > 0 }; - bool hasPerFaceMaterials;// { mesh.parts.size() > 1 }; - if (materialIDCallback) { - if (mesh.parts.size() > 1 || materialIDCallback(0) != 0) { - hasPerFaceMaterials = true; - } - } else { - hasPerFaceMaterials = true; - } + bool hasPerFaceMaterials = (materialIDCallback) ? (mesh.parts.size() > 1 || materialIDCallback(0) != 0 ) : true; bool needsOriginalIndices{ hasDeformers }; int normalsAttributeID{ -1 }; @@ -113,17 +106,13 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes 1, draco::DT_UINT16); } - auto partIndex = 0; draco::FaceIndex face; uint16_t materialID; for (auto& part : mesh.parts) { - if (materialIDCallback) { - materialID = materialIDCallback(partIndex); - } else { - materialID = partIndex; - } + materialID = (materialIDCallback) ? materialIDCallback(partIndex) : partIndex; + auto addFace = [&](QVector& indices, int index, draco::FaceIndex face) { int32_t idx0 = indices[index]; int32_t idx1 = indices[index + 1]; @@ -213,6 +202,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes dracoNode.properties.append(value); dracoMeshNode = dracoNode; + // Mesh compression successful return true return true; } @@ -227,14 +217,12 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model QPair textureContentType; QByteArray textureContent; image::TextureUsage::Type textureType; - // grab the ID for this texture so we can figure out the - // texture type from the loaded materials + if (textureContentTypeCallback) { textureContentType = textureContentTypeCallback(); textureContent = textureContentType.first; textureType = textureContentType.second; } - QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; @@ -277,7 +265,6 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model bakedOutputDir + "/" + bakedTextureFileName }; - // write the new filename into the FBX scene textureChild = bakedTextureFileName.toLocal8Bit(); if (!_bakingTextures.contains(urlToTexture)) { @@ -307,14 +294,14 @@ QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativ // external texture that we'll need to download or find // this is a relative file path which will require different handling - // depending on the location of the original FBX + // depending on the location of the original model if (_modelURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) { - // the absolute path we ran into for the texture in the FBX exists on this machine + // 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 FBX 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()); } } @@ -356,11 +343,11 @@ void ModelBaker::handleBakedTexture() { // use the path to the texture being baked to determine if this was an embedded or a linked texture - // it is embeddded if the texure being baked was inside a folder with the name of the FBX + // 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())) { - // for linked textures we want to save a copy of original texture beside the original FBX + // 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(); @@ -419,21 +406,21 @@ void ModelBaker::handleBakedTexture() { } } -QString ModelBaker::texturePathRelativeToModel(QUrl fbxURL, QUrl textureURL) { - auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); +QString ModelBaker::texturePathRelativeToModel(QUrl modelURL, QUrl textureURL) { + auto modelPath = modelURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); - if (texturePath.startsWith(fbxPath)) { - // texture path is a child of the FBX path, return the texture path without the fbx path - return texturePath.mid(fbxPath.length()); + if (texturePath.startsWith(modelPath)) { + // texture path is a child of the model path, return the texture path without the model path + return texturePath.mid(modelPath.length()); } else { - // the texture path was not a child of the FBX path, return the empty string + // the texture path was not a child of the model path, return the empty string return ""; } } void ModelBaker::checkIfTexturesFinished() { - // check if we're done everything we need to do for this FBX + // 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()) { diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index e132591120..8af95acac8 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -52,7 +52,7 @@ private: QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); void bakeTexture(const QUrl & textureURL, image::TextureUsage::Type textureType, const QDir & outputDir, const QString & bakedFilename, const QByteArray & textureContent); - QString texturePathRelativeToModel(QUrl fbxURL, QUrl textureURL); + QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL); void checkIfTexturesFinished(); QHash _textureNameMatchCount; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 1f6d820b8c..390887d952 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -17,6 +17,22 @@ #include "FBXWriter.h" const double UNIT_SCALE_FACTOR = 100; +const QByteArray PROPERTIES70_NODE_NAME = "Properties70"; +const QByteArray P_NODE_NAME = "P"; +const QByteArray C_NODE_NAME = "C"; +const QByteArray FBX_HEADER_EXTENSION = "FBXHeaderExtension"; +const QByteArray GLOBAL_SETTINGS_NODE_NAME = "GlobalSettings"; +const QByteArray OBJECTS_NODE_NAME = "Objects"; +const QByteArray GEOMETRY_NODE_NAME = "Geometry"; +const QByteArray MODEL_NODE_NAME = "Model"; +const QByteArray MATERIAL_NODE_NAME = "Material"; +const QByteArray TEXTURE_NODE_NAME = "Texture"; +const QByteArray TEXTURENAME_NODE_NAME = "TextureName"; +const QByteArray RELATIVEFILENAME_NODE_NAME = "RelativeFilename"; +const QByteArray CONNECTIONS_NODE_NAME = "Connections"; +const QByteArray CONNECTIONS_NODE_PROPERTY = "OO"; +const QByteArray CONNECTIONS_NODE_PROPERTY_1 = "OP"; +const QByteArray MESH = "Mesh"; OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : @@ -31,7 +47,7 @@ OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGet OBJBaker::~OBJBaker() { if (_tempDir.exists()) { if (!_tempDir.remove(_originalOBJFilePath)) { - qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalOBJFilePath; + qCWarning(model_baking) << "Failed to remove temporary copy of OBJ file:" << _originalOBJFilePath; } if (!_tempDir.rmdir(".")) { qCWarning(model_baking) << "Failed to remove temporary directory:" << _tempDir; @@ -55,8 +71,8 @@ void OBJBaker::bake() { qDebug() << "Made temporary dir " << _tempDir; qDebug() << "Origin file path: " << _originalOBJFilePath; - // trigger startBake once OBJ is loaded - connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::startBake); + // trigger bakeOBJ once OBJ is loaded + connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::bakeOBJ); // make a local copy of the OBJ loadOBJ(); @@ -132,17 +148,17 @@ void OBJBaker::handleOBJNetworkReply() { copyOfOriginal.copy(_originalOutputDir + "/" + _objURL.fileName()); } - // emit our signal to start the import of the obj source copy + // 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 + // add an error to our list stating that the OBJ could not be downloaded handleError("Failed to download " + _objURL.toString()); } } -void OBJBaker::startBake() { - // Read the OBJ +void OBJBaker::bakeOBJ() { + // Read the OBJ file QFile objFile(_originalOBJFilePath); if (!objFile.open(QIODevice::ReadOnly)) { handleError("Error opening " + _originalOBJFilePath + " for reading"); @@ -155,12 +171,12 @@ void OBJBaker::startBake() { OBJReader reader; FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _objURL); - // Write OBJ Data in FBX tree nodes - FBXNode objRoot; - createFBXNodeTree(&objRoot, geometry); + // Write OBJ Data as FBX tree nodes + FBXNode rootNode; + createFBXNodeTree(rootNode, *geometry); // Serialize the resultant FBX tree - auto encodedFBX = FBXWriter::encodeFBX(objRoot); + auto encodedFBX = FBXWriter::encodeFBX(rootNode); // Export as baked FBX auto fileName = _objURL.fileName(); @@ -181,60 +197,65 @@ void OBJBaker::startBake() { // Export successful _outputFiles.push_back(_bakedOBJFilePath); qCDebug(model_baking) << "Exported" << _objURL << "to" << _bakedOBJFilePath; + // Export done emit finished emit finished(); } -void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { +void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Generating FBX Header Node FBXNode headerNode; - headerNode.name = "FBXHeaderExtension"; + headerNode.name = FBX_HEADER_EXTENSION; // Generating global settings node // Required for Unit Scale Factor FBXNode globalSettingsNode; - globalSettingsNode.name = "GlobalSettings"; + globalSettingsNode.name = GLOBAL_SETTINGS_NODE_NAME; + + // Setting the tree hierarchy: GlobalSettings -> Properties70 -> P -> Properties FBXNode properties70Node; - properties70Node.name = "Properties70"; + properties70Node.name = PROPERTIES70_NODE_NAME; FBXNode pNode; - pNode.name = "P"; - setProperties(&pNode); + pNode.name = P_NODE_NAME; + setNodeProperties(pNode); properties70Node.children = { pNode }; globalSettingsNode.children = { properties70Node }; // Generating Object node - _objectNode.name = "Objects"; + _objectNode.name = OBJECTS_NODE_NAME; // Generating Object node's child - Geometry node FBXNode geometryNode; - geometryNode.name = "Geometry"; - setProperties(&geometryNode); + geometryNode.name = GEOMETRY_NODE_NAME; + setNodeProperties(geometryNode); // Compress the mesh information and store in dracoNode - bool hasDeformers = false; - ModelBaker modelBaker; + bool hasDeformers = false; // No concept of deformers for an OBJ FBXNode dracoNode; - this->compressMesh(geometry->meshes[0], hasDeformers, dracoNode); + this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode); geometryNode.children.append(dracoNode); // Generating Object node's child - Model node FBXNode modelNode; - modelNode.name = "Model"; - setProperties(&modelNode); + modelNode.name = MODEL_NODE_NAME; + setNodeProperties(modelNode); + _objectNode.children = { geometryNode, modelNode }; // Generating Objects node's child - Material node - QVector meshParts = geometry->meshes[0].parts; + auto meshParts = geometry.meshes[0].parts; for (auto meshPart : meshParts) { FBXNode materialNode; - materialNode.name = "Material"; - if (geometry->materials.size() == 1) { - foreach(QString materialID, geometry->materials.keys()) { - setMaterialNodeProperties(&materialNode, materialID, geometry); + materialNode.name = MATERIAL_NODE_NAME; + if (geometry.materials.size() == 1) { + // case when no material information is provided, OBJReader considers it as a single default material + foreach(QString materialID, geometry.materials.keys()) { + setMaterialNodeProperties(materialNode, materialID, geometry); } } else { - setMaterialNodeProperties(&materialNode, meshPart.materialID, geometry); + setMaterialNodeProperties(materialNode, meshPart.materialID, geometry); } + _objectNode.children.append(materialNode); } @@ -243,42 +264,48 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // iterate through mesh parts and process the associated textures for (int i = 0;i < meshParts.size();i++) { QString material = meshParts[i].materialID; - FBXMaterial currentMaterial = geometry->materials[material]; + FBXMaterial currentMaterial = geometry.materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { _textureID = _nodeID; _mapTextureMaterial.push_back(QPair(_textureID, i)); - QVariant property0(_nodeID++); + FBXNode textureNode; - textureNode.name = "Texture"; - textureNode.properties = { property0 }; + textureNode.name = TEXTURE_NODE_NAME; + QVariant textureProperty(_nodeID++); + textureNode.properties = { textureProperty }; // Texture node child - TextureName node FBXNode textureNameNode; - textureNameNode.name = "TextureName"; + textureNameNode.name = TEXTURENAME_NODE_NAME; QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; - auto prop0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - textureNameNode.properties = { prop0 }; + textureProperty = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + textureNameNode.properties = { textureProperty }; // Texture node child - Relative Filename node FBXNode relativeFilenameNode; - relativeFilenameNode.name = "RelativeFilename"; + relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME; + QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; // Callback to get Texture content and type getTextureContentTypeCallback textureContentTypeCallback = [=]() { QPair result; - result.first = NULL; + result.first = NULL; // No need of texture content as no embedded textures present in case of an OBJ result.second = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE; return result; }; // Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node - QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback,_originalOutputDir); - QVariant textureProperty0; - textureProperty0 = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); - relativeFilenameNode.properties = { textureProperty0 }; + QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); + if (textureFile) { + textureProperty = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); + } else { + // Baking failed return + return; + } + relativeFilenameNode.properties = { textureProperty }; - textureNode.children = { textureNameNode,relativeFilenameNode }; + textureNode.children = { textureNameNode, relativeFilenameNode }; _objectNode.children.append(textureNode); } @@ -286,107 +313,110 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Generating Connections node FBXNode connectionsNode; - connectionsNode.name = "Connections"; + connectionsNode.name = CONNECTIONS_NODE_NAME; + // connect Geometry to Model - FBXNode cNode1; - cNode1.name = "C"; - QByteArray propertyString("OO"); + FBXNode cNode; + cNode.name = C_NODE_NAME; + QByteArray propertyString(CONNECTIONS_NODE_PROPERTY); QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); qlonglong childID = _geometryID; QVariant property1(childID); qlonglong parentID = _modelID; QVariant property2(parentID); - cNode1.properties = { property0, property1, property2 }; - connectionsNode.children = { cNode1}; + cNode.properties = { property0, property1, property2 }; + connectionsNode.children = { cNode }; // connect all materials to model - for (int i = 0;i < geometry->materials.size();i++) { - FBXNode cNode; - cNode.name = "C"; + 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())); property1 = _materialIDs[i]; property2 = _modelID; - cNode.properties = { property0, property1, property2 }; - connectionsNode.children.append(cNode); + cNode1.properties = { property0, property1, property2 }; + connectionsNode.children.append(cNode1); } // Connect textures to materials for (int i = 0;i < _mapTextureMaterial.size();i++) { FBXNode cNode2; - cNode2.name = "C"; - QByteArray propertyString1("OP"); - property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + cNode2.name = C_NODE_NAME; + propertyString = CONNECTIONS_NODE_PROPERTY_1; + property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); property1 = _mapTextureMaterial[i].first; int matID = _mapTextureMaterial[i].second; property2 = _materialIDs[matID]; - propertyString1 = "AmbientFactor"; - QVariant connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - cNode2.properties = { property0, property1, property2, connectionProperty }; + propertyString = "AmbientFactor"; + QVariant property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + cNode2.properties = { property0, property1, property2, property3 }; connectionsNode.children.append(cNode2); - FBXNode cNode4; - cNode4.name = "C"; - propertyString1 = "OP"; - property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); + FBXNode cNode3; + cNode3.name = C_NODE_NAME; + propertyString = CONNECTIONS_NODE_PROPERTY_1; + property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); property1 = _mapTextureMaterial[i].first; property2 = _materialIDs[matID]; - propertyString1 = "DiffuseColor"; - connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - cNode4.properties = { property0, property1, property2, connectionProperty }; - connectionsNode.children.append(cNode4); + propertyString = "DiffuseColor"; + property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); + cNode3.properties = { property0, property1, property2, property3 }; + connectionsNode.children.append(cNode3); } // Make all generated nodes children of rootNode - objRoot->children = { globalSettingsNode, _objectNode, connectionsNode }; + rootNode.children = { globalSettingsNode, _objectNode, connectionsNode }; } -void OBJBaker::setProperties(FBXNode* parentNode) { - if (parentNode->name == "P") { +// Set properties for P Node and Sub-Object nodes +void OBJBaker::setNodeProperties(FBXNode& parentNode) { + if (parentNode.name == P_NODE_NAME) { std::vector stringProperties{ "UnitScaleFactor", "double", "Number", "" }; std::vector numericProperties{ UNIT_SCALE_FACTOR }; - setPropertiesList(stringProperties, numericProperties, parentNode->properties); - } else if (parentNode->name == "Geometry") { + setPropertiesList(stringProperties, numericProperties, parentNode.properties); + } else if (parentNode.name == GEOMETRY_NODE_NAME) { _geometryID = _nodeID; QVariant property0(_nodeID++); - QByteArray propertyString("Geometry"); + QByteArray propertyString(GEOMETRY_NODE_NAME); QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Mesh"; + propertyString = MESH; QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - parentNode->properties = { property0, property1, property2 }; - } else if (parentNode->name == "Model") { + parentNode.properties = { property0, property1, property2 }; + } else if (parentNode.name == MODEL_NODE_NAME) { _modelID = _nodeID; QVariant property0(_nodeID++); - QByteArray propertyString("Model"); + QByteArray propertyString(MODEL_NODE_NAME); QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Mesh"; + propertyString = MESH; QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - parentNode->properties = { property0, property1, property2 }; + parentNode.properties = { property0, property1, property2 }; } } -void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry) { - // Set materialNode properties +// Set properties for material nodes +void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) { _materialIDs.push_back(_nodeID); QVariant property0(_nodeID++); QByteArray propertyString(material.toLatin1()); QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Mesh"; + propertyString = MESH; 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 FBXNode properties70Node; - properties70Node.name = "Properties70"; + properties70Node.name = PROPERTIES70_NODE_NAME; // Set diffuseColor FBXNode pNodeDiffuseColor; - pNodeDiffuseColor.name = "P"; + pNodeDiffuseColor.name = P_NODE_NAME; std::vector stringProperties{ "DiffuseColor", "Color", "", "A" }; std::vector numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] }; @@ -396,7 +426,7 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material // Set specularColor FBXNode pNodeSpecularColor; - pNodeSpecularColor.name = "P"; + pNodeSpecularColor.name = P_NODE_NAME; stringProperties = { "SpecularColor", "Color", "", "A" }; numericProperties = { currentMaterial.specularColor[0], currentMaterial.specularColor[1], currentMaterial.specularColor[2] }; @@ -406,7 +436,7 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material // Set Shininess FBXNode pNodeShininess; - pNodeShininess.name = "P"; + pNodeShininess.name = P_NODE_NAME; stringProperties = { "Shininess", "Number", "", "A" }; numericProperties = { currentMaterial.shininess }; @@ -416,7 +446,7 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material // Set Opacity FBXNode pNodeOpacity; - pNodeOpacity.name = "P"; + pNodeOpacity.name = P_NODE_NAME; stringProperties = { "Opacity", "Number", "", "A" }; numericProperties = { currentMaterial.opacity }; @@ -424,18 +454,19 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material properties70Node.children.append(pNodeOpacity); - materialNode->children.append(properties70Node); + materialNode.children.append(properties70Node); } -template -void OBJBaker::setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList) { +// Bundle various String and numerical type properties into a single QVariantList +template +void OBJBaker::setPropertiesList(std::vector& stringProperties, std::vector& numericProperties, QVariantList& propertiesList) { foreach(auto stringProperty, stringProperties) { auto propertyValue = QVariant::fromValue(QByteArray(stringProperty.data(), (int)stringProperty.size())); propertiesList.append(propertyValue); } - foreach(auto numberProperty, numericProperties) { - QVariant propertyValue(numberProperty); + foreach(auto numericProperty, numericProperties) { + QVariant propertyValue(numericProperty); propertiesList.append(propertyValue); } } diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index d331d3bde1..d3edc20f61 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -22,17 +22,16 @@ using TextureBakerThreadGetter = std::function; class OBJBaker : public ModelBaker { Q_OBJECT - public: OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir = ""); ~OBJBaker() override; void loadOBJ(); - void createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry); - void setProperties(FBXNode * parentNode); - void setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry); - template - void setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList); + void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry); + void setNodeProperties(FBXNode& parentNode); + void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry); + template + void setPropertiesList(std::vector& stringProperties, std::vector& numericProperties, QVariantList& propertiesList); public slots: virtual void bake() override; @@ -41,7 +40,7 @@ signals: void OBJLoaded(); private slots: - void startBake(); + void bakeOBJ(); void handleOBJNetworkReply(); private: From 98ec4641068e7433acffe2abcac75ad911777e14 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Tue, 24 Oct 2017 16:05:00 -0700 Subject: [PATCH 04/33] Indentation Fixes --- libraries/baking/src/FBXBaker.cpp | 20 ++++++++++++-------- libraries/baking/src/FBXBaker.h | 4 ++-- tools/oven/src/ui/ModelBakeWidget.cpp | 2 +- tools/oven/src/ui/ModelBakeWidget.h | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index f91e829c65..ac7211f77d 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -148,7 +148,7 @@ void FBXBaker::loadSourceFBX() { // check if the FBX is local or first needs to be downloaded if (_fbxURL.isLocalFile()) { // load up the local file - QFile localFBX{ _fbxURL.toLocalFile() }; + QFile localFBX { _fbxURL.toLocalFile() }; qDebug() << "Local file url: " << _fbxURL << _fbxURL.toString() << _fbxURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; @@ -243,7 +243,7 @@ void FBXBaker::importScene() { void FBXBaker::rewriteAndBakeSceneModels() { unsigned int meshIndex = 0; - bool hasDeformers{ false }; + bool hasDeformers { false }; for (FBXNode& rootChild : _rootNode.children) { if (rootChild.name == "Objects") { for (FBXNode& objectChild : rootChild.children) { @@ -283,7 +283,7 @@ void FBXBaker::rewriteAndBakeSceneModels() { objectChild.children.push_back(dracoMeshNode); - static const std::vector nodeNamesToDelete{ + static const std::vector nodeNamesToDelete { // Node data that is packed into the draco mesh "Vertices", "PolygonVertexIndex", @@ -357,17 +357,20 @@ void FBXBaker::rewriteAndBakeSceneTextures() { for (FBXNode& textureChild : object->children) { if (textureChild.name == "RelativeFilename") { - QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; + QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() }; + QFileInfo fbxTextureFileInfo { fbxTextureFileName.replace("\\", "/") }; + QByteArray textureContent = ""; - QFileInfo fbxTextureFileInfo{ fbxTextureFileName.replace("\\", "/") }; - // Callback to get texture content and type from FBXBaker in ModelBaker if (!fbxTextureFileInfo.filePath().isEmpty()) { textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); } + // Callback to get texture content and type getTextureContentTypeCallback textureContentTypeCallback = [=]() { QPair result; - result.first = textureContent;// _textureContent.value(fbxTextureFileName.toLocal8Bit()); + result.first = textureContent; + // grab the ID for this texture so we can figure out the + // texture type from the loaded materials auto textureID{ object->properties[0].toByteArray() }; auto textureType = textureTypes[textureID]; result.second = textureType; @@ -375,7 +378,8 @@ void FBXBaker::rewriteAndBakeSceneTextures() { }; // Compress the texture information and return the new filename to be added into the FBX scene - QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); + QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, + textureContentTypeCallback, _originalOutputDir); // If no errors or warnings have occurred during texture compression add the filename to the FBX scene if (bakedTextureFile) { diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index b76d3699b5..d0f95beebf 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -47,7 +47,7 @@ public slots: signals: void sourceCopyReadyToLoad(); - private slots: +private slots: void bakeSourceCopy(); void handleFBXNetworkReply(); @@ -86,7 +86,7 @@ private: TextureBakerThreadGetter _textureThreadGetter; - bool _pendingErrorEmission{ false }; + bool _pendingErrorEmission { false }; }; #endif // hifi_FBXBaker_h diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 99727b0df6..0bef9f9414 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -164,7 +164,7 @@ void ModelBakeWidget::bakeButtonClicked() { // split the list from the model line edit to see how many models we need to bake auto fileURLStrings = _modelLineEdit->text().split(','); - foreach(QString fileURLString, fileURLStrings) { + foreach (QString fileURLString, fileURLStrings) { // construct a URL from the path in the model file text box QUrl modelToBakeURL(fileURLString); diff --git a/tools/oven/src/ui/ModelBakeWidget.h b/tools/oven/src/ui/ModelBakeWidget.h index e91e5655c6..02e7dde660 100644 --- a/tools/oven/src/ui/ModelBakeWidget.h +++ b/tools/oven/src/ui/ModelBakeWidget.h @@ -54,4 +54,4 @@ private: bool _isFBX = false; }; -#endif // hifi_ModelBakeWidget_h \ No newline at end of file +#endif // hifi_ModelBakeWidget_h From 79c1e84c76c844d8da964576219bd579120c5511 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Tue, 24 Oct 2017 16:15:20 -0700 Subject: [PATCH 05/33] More indentation/spacing fixes --- tools/oven/src/Oven.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index 764f4518c1..973eafa1f5 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -26,7 +26,6 @@ #include #include - static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; static const QString CLI_INPUT_PARAMETER = "i"; From dccf449cf7cf0af459948f2bf7ad7eb4aaf18346 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Tue, 24 Oct 2017 16:20:39 -0700 Subject: [PATCH 06/33] edited comments --- libraries/baking/src/FBXBaker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index ac7211f77d..c26a3d81a8 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -265,7 +265,7 @@ void FBXBaker::rewriteAndBakeSceneModels() { // TODO Pull this out of _geometry instead so we don't have to reprocess it auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); - // Callback to get MaterialID from FBXBaker in ModelBaker + // Callback to get MaterialID getMaterialIDCallback materialIDcallback = [=](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; // Compress mesh information and store in dracoMeshNode From 221b293dafa6726e350942bfbd6d121826c4dd81 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Tue, 24 Oct 2017 16:58:35 -0700 Subject: [PATCH 07/33] Indentation Fixes --- libraries/baking/src/OBJBaker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 390887d952..3303bbd828 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -364,7 +364,6 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { connectionsNode.children.append(cNode3); } - // Make all generated nodes children of rootNode rootNode.children = { globalSettingsNode, _objectNode, connectionsNode }; } From 54f9d52aa11035ba508e202e16f82a4c4017a232 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 14:15:55 -0700 Subject: [PATCH 08/33] Moved _textureContent to parent class ModelBaker --- libraries/baking/src/FBXBaker.cpp | 33 ++++------------------------- libraries/baking/src/FBXBaker.h | 3 --- libraries/baking/src/ModelBaker.cpp | 14 ++++++------ libraries/baking/src/ModelBaker.h | 10 ++++++--- libraries/baking/src/OBJBaker.cpp | 7 ++---- 5 files changed, 19 insertions(+), 48 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index c26a3d81a8..28b70c88a6 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -365,21 +365,18 @@ void FBXBaker::rewriteAndBakeSceneTextures() { textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); } - // Callback to get texture content and type - getTextureContentTypeCallback textureContentTypeCallback = [=]() { - QPair result; - result.first = textureContent; + // Callback to get texture type + getTextureTypeCallback textureTypeCallback = [=]() { // grab the ID for this texture so we can figure out the // texture type from the loaded materials auto textureID{ object->properties[0].toByteArray() }; auto textureType = textureTypes[textureID]; - result.second = textureType; - return result; + return textureType; }; // Compress the texture information and return the new filename to be added into the FBX scene QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, - textureContentTypeCallback, _originalOutputDir); + textureTypeCallback, _originalOutputDir); // If no errors or warnings have occurred during texture compression add the filename to the FBX scene if (bakedTextureFile) { @@ -431,25 +428,3 @@ void FBXBaker::exportScene() { qCDebug(model_baking) << "Exported" << _fbxURL << "with re-written paths to" << _bakedFBXFilePath; } - -void FBXBaker::checkIfTexturesFinished() { - // check if we're done everything we need to do for this FBX - // and emit our finished signal if we're done - - 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 - - if (_pendingErrorEmission) { - setIsFinished(true); - } - - return; - } else { - qCDebug(model_baking) << "Finished baking, emitting finsihed" << _fbxURL; - - setIsFinished(true); - } - } -} diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index d0f95beebf..4bf883bf2f 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -62,13 +62,10 @@ private: void exportScene(); void removeEmbeddedMediaFolder(); - void checkIfTexturesFinished(); - QUrl _fbxURL; FBXNode _rootNode; FBXGeometry* _geometry; - QHash _textureContent; QString _bakedFBXFilePath; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 242d9794ef..dafd932135 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -207,21 +207,17 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes } QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl modelURL, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, - getTextureContentTypeCallback textureContentTypeCallback, const QString& originalOutputDir) { + getTextureTypeCallback textureTypeCallback, const QString& originalOutputDir) { _modelURL = modelURL; _textureThreadGetter = textureThreadGetter; _originalOutputDir = originalOutputDir; static QByteArray textureChild; - - QPair textureContentType; QByteArray textureContent; image::TextureUsage::Type textureType; - if (textureContentTypeCallback) { - textureContentType = textureContentTypeCallback(); - textureContent = textureContentType.first; - textureType = textureContentType.second; + if (textureTypeCallback) { + textureType = textureTypeCallback(); } QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; @@ -244,7 +240,9 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model // check if this was an embedded texture that we already have in-memory content for // figure out the URL to this texture, embedded or external - qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); + if (!modelTextureFileInfo.filePath().isEmpty()) { + textureContent = _textureContent.value(modelTextureFileName.toLocal8Bit()); + } auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull()); QString bakedTextureFileName; diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 8af95acac8..7f8efdf887 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -28,7 +28,7 @@ using TextureBakerThreadGetter = std::function; using getMaterialIDCallback = std::function ; -using getTextureContentTypeCallback = std::function()>; +using getTextureTypeCallback = std::function; class ModelBaker : public Baker{ Q_OBJECT @@ -37,8 +37,12 @@ public: ModelBaker(); bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); QByteArray* compressTexture(QString textureFileName, QUrl modelUrl, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, - getTextureContentTypeCallback textureContentTypeCallback = NULL, const QString& originalOutputDir = ""); + getTextureTypeCallback textureTypeCallback = NULL, const QString& originalOutputDir = ""); virtual void setWasAborted(bool wasAborted) override; + +protected: + void checkIfTexturesFinished(); + QHash _textureContent; public slots: virtual void bake() override; @@ -53,7 +57,7 @@ private: void bakeTexture(const QUrl & textureURL, image::TextureUsage::Type textureType, const QDir & outputDir, const QString & bakedFilename, const QByteArray & textureContent); QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL); - void checkIfTexturesFinished(); + QHash _textureNameMatchCount; QHash _remappedTexturePaths; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 3303bbd828..076b78501b 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -288,11 +288,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; // Callback to get Texture content and type - getTextureContentTypeCallback textureContentTypeCallback = [=]() { - QPair result; - result.first = NULL; // No need of texture content as no embedded textures present in case of an OBJ - result.second = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE; - return result; + 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 From d7f2e21dcab8fd907f33043cb0ab107f73e214b0 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 16:13:06 -0700 Subject: [PATCH 09/33] Moved common variables between base and derived classes to base class --- libraries/baking/src/FBXBaker.cpp | 51 ++++++++++++++--------------- libraries/baking/src/FBXBaker.h | 11 +------ libraries/baking/src/ModelBaker.cpp | 21 +++++++----- libraries/baking/src/ModelBaker.h | 17 ++++++---- libraries/baking/src/OBJBaker.cpp | 43 +++++++++++------------- libraries/baking/src/OBJBaker.h | 4 --- 6 files changed, 68 insertions(+), 79 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 28b70c88a6..9e39f60dd5 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -34,14 +34,12 @@ #include "FBXBaker.h" FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir) : - _fbxURL(fbxURL), - _bakedOutputDir(bakedOutputDir), - _originalOutputDir(originalOutputDir), - _textureThreadGetter(textureThreadGetter) { + const QString& bakedOutputDir, const QString& originalOutputDir) : + ModelBaker(fbxURL, textureThreadGetter, bakedOutputDir, originalOutputDir) +{ } - + FBXBaker::~FBXBaker() { if (_tempDir.exists()) { if (!_tempDir.remove(_originalFBXFilePath)) { @@ -64,7 +62,7 @@ void FBXBaker::abort() { } void FBXBaker::bake() { - qDebug() << "FBXBaker" << _fbxURL << "bake starting"; + qDebug() << "FBXBaker" << _modelURL << "bake starting"; auto tempDir = PathUtils::generateTemporaryDir(); @@ -75,7 +73,7 @@ void FBXBaker::bake() { _tempDir = tempDir; - _originalFBXFilePath = _tempDir.filePath(_fbxURL.fileName()); + _originalFBXFilePath = _tempDir.filePath(_modelURL.fileName()); qDebug() << "Made temporary dir " << _tempDir; qDebug() << "Origin file path: " << _originalFBXFilePath; @@ -146,22 +144,22 @@ void FBXBaker::setupOutputFolder() { void FBXBaker::loadSourceFBX() { // check if the FBX is local or first needs to be downloaded - if (_fbxURL.isLocalFile()) { + if (_modelURL.isLocalFile()) { // load up the local file - QFile localFBX { _fbxURL.toLocalFile() }; + QFile localFBX { _modelURL.toLocalFile() }; - qDebug() << "Local file url: " << _fbxURL << _fbxURL.toString() << _fbxURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; + qDebug() << "Local file url: " << _modelURL << _modelURL.toString() << _modelURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; if (!localFBX.exists()) { //QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), ""); - handleError("Could not find " + _fbxURL.toString()); + handleError("Could not find " + _modelURL.toString()); return; } // make a copy in the output folder if (!_originalOutputDir.isEmpty()) { - qDebug() << "Copying to: " << _originalOutputDir << "/" << _fbxURL.fileName(); - localFBX.copy(_originalOutputDir + "/" + _fbxURL.fileName()); + qDebug() << "Copying to: " << _originalOutputDir << "/" << _modelURL.fileName(); + localFBX.copy(_originalOutputDir + "/" + _modelURL.fileName()); } localFBX.copy(_originalFBXFilePath); @@ -179,9 +177,9 @@ void FBXBaker::loadSourceFBX() { networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - networkRequest.setUrl(_fbxURL); + networkRequest.setUrl(_modelURL); - qCDebug(model_baking) << "Downloading" << _fbxURL; + qCDebug(model_baking) << "Downloading" << _modelURL; auto networkReply = networkAccessManager.get(networkRequest); connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply); @@ -192,7 +190,7 @@ void FBXBaker::handleFBXNetworkReply() { auto requestReply = qobject_cast(sender()); if (requestReply->error() == QNetworkReply::NoError) { - qCDebug(model_baking) << "Downloaded" << _fbxURL; + qCDebug(model_baking) << "Downloaded" << _modelURL; // grab the contents of the reply and make a copy in the output folder QFile copyOfOriginal(_originalFBXFilePath); @@ -201,11 +199,11 @@ void FBXBaker::handleFBXNetworkReply() { 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 " + _fbxURL.toString() + " (Failed to open " + _originalFBXFilePath + ")"); + handleError("Could not create copy of " + _modelURL.toString() + " (Failed to open " + _originalFBXFilePath + ")"); return; } if (copyOfOriginal.write(requestReply->readAll()) == -1) { - handleError("Could not create copy of " + _fbxURL.toString() + " (Failed to write)"); + handleError("Could not create copy of " + _modelURL.toString() + " (Failed to write)"); return; } @@ -213,14 +211,14 @@ void FBXBaker::handleFBXNetworkReply() { copyOfOriginal.close(); if (!_originalOutputDir.isEmpty()) { - copyOfOriginal.copy(_originalOutputDir + "/" + _fbxURL.fileName()); + 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 " + _fbxURL.toString()); + handleError("Failed to download " + _modelURL.toString()); } } @@ -235,9 +233,9 @@ void FBXBaker::importScene() { FBXReader reader; - qCDebug(model_baking) << "Parsing" << _fbxURL; + qCDebug(model_baking) << "Parsing" << _modelURL; _rootNode = reader._rootNode = reader.parseFBX(&fbxFile); - _geometry = reader.extractFBXGeometry({}, _fbxURL.toString()); + _geometry = reader.extractFBXGeometry({}, _modelURL.toString()); _textureContent = reader._textureContent; } @@ -375,8 +373,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() { }; // Compress the texture information and return the new filename to be added into the FBX scene - QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, - textureTypeCallback, _originalOutputDir); + QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, textureTypeCallback); // If no errors or warnings have occurred during texture compression add the filename to the FBX scene if (bakedTextureFile) { @@ -407,7 +404,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() { void FBXBaker::exportScene() { // save the relative path to this FBX inside our passed output folder - auto fileName = _fbxURL.fileName(); + auto fileName = _modelURL.fileName(); auto baseName = fileName.left(fileName.lastIndexOf('.')); auto bakedFilename = baseName + BAKED_FBX_EXTENSION; @@ -426,5 +423,5 @@ void FBXBaker::exportScene() { _outputFiles.push_back(_bakedFBXFilePath); - qCDebug(model_baking) << "Exported" << _fbxURL << "with re-written paths to" << _bakedFBXFilePath; + qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedFBXFilePath; } diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 4bf883bf2f..84215ec75e 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -37,7 +37,7 @@ public: const QString& bakedOutputDir, const QString& originalOutputDir = ""); ~FBXBaker() override; - QUrl getFBXUrl() const { return _fbxURL; } + QUrl getFBXUrl() const { return _modelURL; } QString getBakedFBXFilePath() const { return _bakedFBXFilePath; } public slots: @@ -62,18 +62,11 @@ private: void exportScene(); void removeEmbeddedMediaFolder(); - QUrl _fbxURL; - FBXNode _rootNode; FBXGeometry* _geometry; QString _bakedFBXFilePath; - QString _bakedOutputDir; - - // If set, the original FBX and textures will also be copied here - QString _originalOutputDir; - QDir _tempDir; QString _originalFBXFilePath; @@ -81,8 +74,6 @@ private: QHash _textureNameMatchCount; QHash _remappedTexturePaths; - TextureBakerThreadGetter _textureThreadGetter; - bool _pendingErrorEmission { false }; }; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index dafd932135..25dcc8f876 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -29,7 +29,15 @@ #pragma warning( pop ) #endif -ModelBaker::ModelBaker() {} +ModelBaker::ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThreadGetter, + const QString& bakedOutputDir, const QString& originalOutputDir) : + _modelURL(modelURL), + _textureThreadGetter(textureThreadGetter), + _bakedOutputDir(bakedOutputDir), + _originalOutputDir(originalOutputDir) +{ + +} void ModelBaker::bake() {} @@ -206,12 +214,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes return true; } -QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl modelURL, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, - getTextureTypeCallback textureTypeCallback, const QString& originalOutputDir) { - _modelURL = modelURL; - _textureThreadGetter = textureThreadGetter; - _originalOutputDir = originalOutputDir; - +QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTextureTypeCallback textureTypeCallback) { static QByteArray textureChild; QByteArray textureContent; image::TextureUsage::Type textureType; @@ -260,7 +263,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model << "to" << bakedTextureFileName; QString bakedTextureFilePath{ - bakedOutputDir + "/" + bakedTextureFileName + _bakedOutputDir + "/" + bakedTextureFileName }; textureChild = bakedTextureFileName.toLocal8Bit(); @@ -269,7 +272,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously - bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent); + bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); } } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 7f8efdf887..e0f68cd5c8 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -34,15 +34,20 @@ class ModelBaker : public Baker{ Q_OBJECT public: - ModelBaker(); + ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThreadGetter, + const QString& bakedOutputDir, const QString& originalOutputDir); bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); - QByteArray* compressTexture(QString textureFileName, QUrl modelUrl, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, - getTextureTypeCallback textureTypeCallback = NULL, const QString& originalOutputDir = ""); + QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL); virtual void setWasAborted(bool wasAborted) override; protected: void checkIfTexturesFinished(); + QHash _textureContent; + QString _bakedOutputDir; + QString _originalOutputDir; + TextureBakerThreadGetter _textureThreadGetter; + QUrl _modelURL; public slots: virtual void bake() override; @@ -61,10 +66,10 @@ private: QHash _textureNameMatchCount; QHash _remappedTexturePaths; - QUrl _modelURL; + //QUrl _modelURL; QMultiHash> _bakingTextures; - TextureBakerThreadGetter _textureThreadGetter; - QString _originalOutputDir; + //TextureBakerThreadGetter _textureThreadGetter; + //QString _originalOutputDir; bool _pendingErrorEmission{ false }; }; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 076b78501b..697e5f7116 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -36,10 +36,7 @@ const QByteArray MESH = "Mesh"; OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : - _objURL(objURL), - _bakedOutputDir(bakedOutputDir), - _originalOutputDir(originalOutputDir), - _textureThreadGetter(textureThreadGetter) + ModelBaker(objURL, textureThreadGetter, bakedOutputDir, originalOutputDir) { } @@ -56,7 +53,7 @@ OBJBaker::~OBJBaker() { } void OBJBaker::bake() { - qDebug() << "OBJBaker" << _objURL << "bake starting"; + qDebug() << "OBJBaker" << _modelURL << "bake starting"; auto tempDir = PathUtils::generateTemporaryDir(); @@ -67,7 +64,7 @@ void OBJBaker::bake() { _tempDir = tempDir; - _originalOBJFilePath = _tempDir.filePath(_objURL.fileName()); + _originalOBJFilePath = _tempDir.filePath(_modelURL.fileName()); qDebug() << "Made temporary dir " << _tempDir; qDebug() << "Origin file path: " << _originalOBJFilePath; @@ -80,21 +77,21 @@ void OBJBaker::bake() { void OBJBaker::loadOBJ() { // check if the OBJ is local or it needs to be downloaded - if (_objURL.isLocalFile()) { + if (_modelURL.isLocalFile()) { // loading the local OBJ - QFile localOBJ{ _objURL.toLocalFile() }; + QFile localOBJ{ _modelURL.toLocalFile() }; - qDebug() << "Local file url: " << _objURL << _objURL.toString() << _objURL.toLocalFile() << ", copying to: " << _originalOBJFilePath; + qDebug() << "Local file url: " << _modelURL << _modelURL.toString() << _modelURL.toLocalFile() << ", copying to: " << _originalOBJFilePath; if (!localOBJ.exists()) { - handleError("Could not find " + _objURL.toString()); + handleError("Could not find " + _modelURL.toString()); return; } // make a copy in the output folder if (!_originalOutputDir.isEmpty()) { - qDebug() << "Copying to: " << _originalOutputDir << "/" << _objURL.fileName(); - localOBJ.copy(_originalOutputDir + "/" + _objURL.fileName()); + qDebug() << "Copying to: " << _originalOutputDir << "/" << _modelURL.fileName(); + localOBJ.copy(_originalOutputDir + "/" + _modelURL.fileName()); } localOBJ.copy(_originalOBJFilePath); @@ -111,9 +108,9 @@ void OBJBaker::loadOBJ() { networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - networkRequest.setUrl(_objURL); + networkRequest.setUrl(_modelURL); - qCDebug(model_baking) << "Downloading" << _objURL; + qCDebug(model_baking) << "Downloading" << _modelURL; auto networkReply = networkAccessManager.get(networkRequest); connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply); @@ -124,7 +121,7 @@ void OBJBaker::handleOBJNetworkReply() { auto requestReply = qobject_cast(sender()); if (requestReply->error() == QNetworkReply::NoError) { - qCDebug(model_baking) << "Downloaded" << _objURL; + qCDebug(model_baking) << "Downloaded" << _modelURL; // grab the contents of the reply and make a copy in the output folder QFile copyOfOriginal(_originalOBJFilePath); @@ -133,11 +130,11 @@ void OBJBaker::handleOBJNetworkReply() { 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 " + _objURL.toString() + " (Failed to open " + _originalOBJFilePath + ")"); + handleError("Could not create copy of " + _modelURL.toString() + " (Failed to open " + _originalOBJFilePath + ")"); return; } if (copyOfOriginal.write(requestReply->readAll()) == -1) { - handleError("Could not create copy of " + _objURL.toString() + " (Failed to write)"); + handleError("Could not create copy of " + _modelURL.toString() + " (Failed to write)"); return; } @@ -145,14 +142,14 @@ void OBJBaker::handleOBJNetworkReply() { copyOfOriginal.close(); if (!_originalOutputDir.isEmpty()) { - copyOfOriginal.copy(_originalOutputDir + "/" + _objURL.fileName()); + 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 " + _objURL.toString()); + handleError("Failed to download " + _modelURL.toString()); } } @@ -169,7 +166,7 @@ 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, _objURL); + FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL); // Write OBJ Data as FBX tree nodes FBXNode rootNode; @@ -179,7 +176,7 @@ void OBJBaker::bakeOBJ() { auto encodedFBX = FBXWriter::encodeFBX(rootNode); // Export as baked FBX - auto fileName = _objURL.fileName(); + auto fileName = _modelURL.fileName(); auto baseName = fileName.left(fileName.lastIndexOf('.')); auto bakedFilename = baseName + ".baked.fbx"; @@ -196,7 +193,7 @@ void OBJBaker::bakeOBJ() { // Export successful _outputFiles.push_back(_bakedOBJFilePath); - qCDebug(model_baking) << "Exported" << _objURL << "to" << _bakedOBJFilePath; + qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedOBJFilePath; // Export done emit finished emit finished(); @@ -293,7 +290,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { }; // Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node - QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); + QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback); if (textureFile) { textureProperty = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); } else { diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index d3edc20f61..3a3cb63fcb 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -45,13 +45,9 @@ private slots: private: qlonglong _nodeID = 0; - QUrl _objURL; QString _bakedOBJFilePath; - QString _bakedOutputDir; - QString _originalOutputDir; QDir _tempDir; QString _originalOBJFilePath; - TextureBakerThreadGetter _textureThreadGetter; QMultiHash> _bakingTextures; qlonglong _geometryID; From 8d3f11a990b9dddd270801f5748367a98be18c27 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 16:27:09 -0700 Subject: [PATCH 10/33] moved code to set _textureContent to ModelBaker class --- libraries/baking/src/FBXBaker.cpp | 6 ------ libraries/baking/src/ModelBaker.cpp | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 9e39f60dd5..5085875e07 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -356,12 +356,6 @@ void FBXBaker::rewriteAndBakeSceneTextures() { if (textureChild.name == "RelativeFilename") { QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() }; - QFileInfo fbxTextureFileInfo { fbxTextureFileName.replace("\\", "/") }; - - QByteArray textureContent = ""; - if (!fbxTextureFileInfo.filePath().isEmpty()) { - textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - } // Callback to get texture type getTextureTypeCallback textureTypeCallback = [=]() { diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 25dcc8f876..2575a82dfe 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -216,7 +216,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTextureTypeCallback textureTypeCallback) { static QByteArray textureChild; - QByteArray textureContent; + QByteArray textureContent = ""; image::TextureUsage::Type textureType; if (textureTypeCallback) { From 854c190f32990aea2b0edf129ffed9088eecd288 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 17:10:12 -0700 Subject: [PATCH 11/33] fixed names of protected members according to naming conventions --- libraries/baking/src/FBXBaker.cpp | 62 ++++++++++++++--------------- libraries/baking/src/FBXBaker.h | 2 +- libraries/baking/src/ModelBaker.cpp | 38 +++++++++--------- libraries/baking/src/ModelBaker.h | 10 ++--- libraries/baking/src/OBJBaker.cpp | 42 +++++++++---------- 5 files changed, 77 insertions(+), 77 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 5085875e07..d6d9daa433 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -39,7 +39,7 @@ FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGet { } - + FBXBaker::~FBXBaker() { if (_tempDir.exists()) { if (!_tempDir.remove(_originalFBXFilePath)) { @@ -62,7 +62,7 @@ void FBXBaker::abort() { } void FBXBaker::bake() { - qDebug() << "FBXBaker" << _modelURL << "bake starting"; + qDebug() << "FBXBaker" << modelURL << "bake starting"; auto tempDir = PathUtils::generateTemporaryDir(); @@ -73,7 +73,7 @@ void FBXBaker::bake() { _tempDir = tempDir; - _originalFBXFilePath = _tempDir.filePath(_modelURL.fileName()); + _originalFBXFilePath = _tempDir.filePath(modelURL.fileName()); qDebug() << "Made temporary dir " << _tempDir; qDebug() << "Origin file path: " << _originalFBXFilePath; @@ -124,19 +124,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; } } @@ -144,22 +144,22 @@ 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: " << _originalFBXFilePath; + qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; 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(_originalFBXFilePath); @@ -177,9 +177,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); @@ -190,7 +190,7 @@ void FBXBaker::handleFBXNetworkReply() { auto requestReply = qobject_cast(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(_originalFBXFilePath); @@ -199,26 +199,26 @@ void FBXBaker::handleFBXNetworkReply() { 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 " + _originalFBXFilePath + ")"); + handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + _originalFBXFilePath + ")"); 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()); } } @@ -233,10 +233,10 @@ void FBXBaker::importScene() { FBXReader reader; - qCDebug(model_baking) << "Parsing" << _modelURL; + qCDebug(model_baking) << "Parsing" << modelURL; _rootNode = reader._rootNode = reader.parseFBX(&fbxFile); - _geometry = reader.extractFBXGeometry({}, _modelURL.toString()); - _textureContent = reader._textureContent; + _geometry = reader.extractFBXGeometry({}, modelURL.toString()); + textureContentMap = reader._textureContent; } void FBXBaker::rewriteAndBakeSceneModels() { @@ -398,11 +398,11 @@ 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; - _bakedFBXFilePath = _bakedOutputDir + "/" + bakedFilename; + _bakedFBXFilePath = bakedOutputDir + "/" + bakedFilename; auto fbxData = FBXWriter::encodeFBX(_rootNode); @@ -417,5 +417,5 @@ void FBXBaker::exportScene() { _outputFiles.push_back(_bakedFBXFilePath); - qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedFBXFilePath; + qCDebug(model_baking) << "Exported" << modelURL << "with re-written paths to" << _bakedFBXFilePath; } diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 84215ec75e..53f4984d93 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -37,7 +37,7 @@ public: const QString& bakedOutputDir, const QString& originalOutputDir = ""); ~FBXBaker() override; - QUrl getFBXUrl() const { return _modelURL; } + QUrl getFBXUrl() const { return modelURL; } QString getBakedFBXFilePath() const { return _bakedFBXFilePath; } public slots: diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 2575a82dfe..3490ca69f5 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -31,10 +31,10 @@ ModelBaker::ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : - _modelURL(modelURL), - _textureThreadGetter(textureThreadGetter), - _bakedOutputDir(bakedOutputDir), - _originalOutputDir(originalOutputDir) + modelURL(modelURL), + textureThreadGetter(textureThreadGetter), + bakedOutputDir(bakedOutputDir), + originalOutputDir(originalOutputDir) { } @@ -244,7 +244,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture // figure out the URL to this texture, embedded or external if (!modelTextureFileInfo.filePath().isEmpty()) { - textureContent = _textureContent.value(modelTextureFileName.toLocal8Bit()); + textureContent = textureContentMap.value(modelTextureFileName.toLocal8Bit()); } auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull()); @@ -263,7 +263,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture << "to" << bakedTextureFileName; QString bakedTextureFilePath{ - _bakedOutputDir + "/" + bakedTextureFileName + bakedOutputDir + "/" + bakedTextureFileName }; textureChild = bakedTextureFileName.toLocal8Bit(); @@ -272,7 +272,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously - bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); + bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent); } } @@ -286,7 +286,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 @@ -296,14 +296,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()); } } } @@ -328,7 +328,7 @@ void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type t _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"); } @@ -339,7 +339,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 @@ -347,16 +347,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) { @@ -365,10 +365,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; } } @@ -435,7 +435,7 @@ void ModelBaker::checkIfTexturesFinished() { return; } else { - qCDebug(model_baking) << "Finished baking, emitting finished" << _modelURL; + qCDebug(model_baking) << "Finished baking, emitting finished" << modelURL; setIsFinished(true); } @@ -487,7 +487,7 @@ void ModelBaker::setWasAborted(bool wasAborted) { Baker::setWasAborted(wasAborted); if (wasAborted) { - qCDebug(model_baking) << "Aborted baking" << _modelURL; + qCDebug(model_baking) << "Aborted baking" << modelURL; } } } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index e0f68cd5c8..955aa1acb8 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -43,11 +43,11 @@ public: protected: void checkIfTexturesFinished(); - QHash _textureContent; - QString _bakedOutputDir; - QString _originalOutputDir; - TextureBakerThreadGetter _textureThreadGetter; - QUrl _modelURL; + QHash textureContentMap; + QString bakedOutputDir; + QString originalOutputDir; + TextureBakerThreadGetter textureThreadGetter; + QUrl modelURL; public slots: virtual void bake() override; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 697e5f7116..5be36b3ff7 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -53,7 +53,7 @@ OBJBaker::~OBJBaker() { } void OBJBaker::bake() { - qDebug() << "OBJBaker" << _modelURL << "bake starting"; + qDebug() << "OBJBaker" << modelURL << "bake starting"; auto tempDir = PathUtils::generateTemporaryDir(); @@ -64,7 +64,7 @@ void OBJBaker::bake() { _tempDir = tempDir; - _originalOBJFilePath = _tempDir.filePath(_modelURL.fileName()); + _originalOBJFilePath = _tempDir.filePath(modelURL.fileName()); qDebug() << "Made temporary dir " << _tempDir; qDebug() << "Origin file path: " << _originalOBJFilePath; @@ -77,21 +77,21 @@ 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: " << _originalOBJFilePath; + qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << _originalOBJFilePath; 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(_originalOBJFilePath); @@ -108,9 +108,9 @@ 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); + networkRequest.setUrl(modelURL); - qCDebug(model_baking) << "Downloading" << _modelURL; + qCDebug(model_baking) << "Downloading" << modelURL; auto networkReply = networkAccessManager.get(networkRequest); connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply); @@ -121,7 +121,7 @@ void OBJBaker::handleOBJNetworkReply() { auto requestReply = qobject_cast(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(_originalOBJFilePath); @@ -130,26 +130,26 @@ void OBJBaker::handleOBJNetworkReply() { 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 " + _originalOBJFilePath + ")"); + handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + _originalOBJFilePath + ")"); 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()); } } @@ -166,7 +166,7 @@ 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; @@ -176,11 +176,11 @@ 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"; - _bakedOBJFilePath = _bakedOutputDir + "/" + bakedFilename; + _bakedOBJFilePath = bakedOutputDir + "/" + bakedFilename; QFile bakedFile; bakedFile.setFileName(_bakedOBJFilePath); @@ -193,7 +193,7 @@ void OBJBaker::bakeOBJ() { // Export successful _outputFiles.push_back(_bakedOBJFilePath); - qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedOBJFilePath; + qCDebug(model_baking) << "Exported" << modelURL << "to" << _bakedOBJFilePath; // Export done emit finished emit finished(); From 10eb258d3b6b266be8688c84eb1fdc9d2f22b362 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 18:31:50 -0700 Subject: [PATCH 12/33] moved more common members to ModelBaker parent class --- libraries/baking/src/FBXBaker.cpp | 48 ++++++++++++++--------------- libraries/baking/src/FBXBaker.h | 9 +----- libraries/baking/src/ModelBaker.cpp | 18 +++++------ libraries/baking/src/ModelBaker.h | 10 +++--- libraries/baking/src/OBJBaker.cpp | 42 ++++++++++++------------- libraries/baking/src/OBJBaker.h | 5 --- 6 files changed, 60 insertions(+), 72 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index d6d9daa433..8df9964d0c 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -41,12 +41,12 @@ FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGet } FBXBaker::~FBXBaker() { - if (_tempDir.exists()) { - if (!_tempDir.remove(_originalFBXFilePath)) { - qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalFBXFilePath; + if (modelTempDir.exists()) { + if (!modelTempDir.remove(originalModelFilePath)) { + qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << originalModelFilePath; } - if (!_tempDir.rmdir(".")) { - qCWarning(model_baking) << "Failed to remove temporary directory:" << _tempDir; + if (!modelTempDir.rmdir(".")) { + qCWarning(model_baking) << "Failed to remove temporary directory:" << modelTempDir; } } } @@ -56,12 +56,12 @@ void FBXBaker::abort() { // tell our underlying TextureBaker instances to abort // the FBXBaker will wait until all are aborted before emitting its own abort signal - for (auto& textureBaker : _bakingTextures) { + for (auto& textureBaker : bakingTextures) { textureBaker->abort(); } } -void FBXBaker::bake() { +void FBXBaker::bake() { qDebug() << "FBXBaker" << modelURL << "bake starting"; auto tempDir = PathUtils::generateTemporaryDir(); @@ -71,11 +71,11 @@ void FBXBaker::bake() { return; } - _tempDir = tempDir; + modelTempDir = tempDir; - _originalFBXFilePath = _tempDir.filePath(modelURL.fileName()); - qDebug() << "Made temporary dir " << _tempDir; - qDebug() << "Origin file path: " << _originalFBXFilePath; + 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 setupOutputFolder(); @@ -148,7 +148,7 @@ void FBXBaker::loadSourceFBX() { // load up the local file QFile localFBX { modelURL.toLocalFile() }; - qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << _originalFBXFilePath; + qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << originalModelFilePath; if (!localFBX.exists()) { //QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), ""); @@ -162,7 +162,7 @@ void FBXBaker::loadSourceFBX() { localFBX.copy(originalOutputDir + "/" + modelURL.fileName()); } - localFBX.copy(_originalFBXFilePath); + localFBX.copy(originalModelFilePath); // emit our signal to start the import of the FBX source copy emit sourceCopyReadyToLoad(); @@ -193,13 +193,13 @@ void FBXBaker::handleFBXNetworkReply() { qCDebug(model_baking) << "Downloaded" << modelURL; // grab the contents of the reply and make a copy in the output folder - QFile copyOfOriginal(_originalFBXFilePath); + QFile copyOfOriginal(originalModelFilePath); - qDebug(model_baking) << "Writing copy of original FBX to" << _originalFBXFilePath << 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 " + _originalFBXFilePath + ")"); + handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + originalModelFilePath + ")"); return; } if (copyOfOriginal.write(requestReply->readAll()) == -1) { @@ -223,11 +223,11 @@ void FBXBaker::handleFBXNetworkReply() { } void FBXBaker::importScene() { - qDebug() << "file path: " << _originalFBXFilePath.toLocal8Bit().data() << QDir(_originalFBXFilePath).exists(); + qDebug() << "file path: " << originalModelFilePath.toLocal8Bit().data() << QDir(originalModelFilePath).exists(); - QFile fbxFile(_originalFBXFilePath); + QFile fbxFile(originalModelFilePath); if (!fbxFile.open(QIODevice::ReadOnly)) { - handleError("Error opening " + _originalFBXFilePath + " for reading"); + handleError("Error opening " + originalModelFilePath + " for reading"); return; } @@ -402,20 +402,20 @@ void FBXBaker::exportScene() { auto baseName = fileName.left(fileName.lastIndexOf('.')); auto bakedFilename = baseName + BAKED_FBX_EXTENSION; - _bakedFBXFilePath = bakedOutputDir + "/" + bakedFilename; + bakedModelFilePath = bakedOutputDir + "/" + bakedFilename; auto fbxData = FBXWriter::encodeFBX(_rootNode); - QFile bakedFile(_bakedFBXFilePath); + QFile bakedFile(bakedModelFilePath); if (!bakedFile.open(QIODevice::WriteOnly)) { - handleError("Error opening " + _bakedFBXFilePath + " for writing"); + handleError("Error opening " + bakedModelFilePath + " for writing"); return; } bakedFile.write(fbxData); - _outputFiles.push_back(_bakedFBXFilePath); + _outputFiles.push_back(bakedModelFilePath); - qCDebug(model_baking) << "Exported" << modelURL << "with re-written paths to" << _bakedFBXFilePath; + qCDebug(model_baking) << "Exported" << modelURL << "with re-written paths to" << bakedModelFilePath; } diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 53f4984d93..941c86b703 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -38,7 +38,7 @@ public: ~FBXBaker() override; QUrl getFBXUrl() const { return modelURL; } - QString getBakedFBXFilePath() const { return _bakedFBXFilePath; } + QString getBakedFBXFilePath() const { return bakedModelFilePath; } public slots: virtual void bake() override; @@ -64,13 +64,6 @@ private: FBXNode _rootNode; FBXGeometry* _geometry; - - QString _bakedFBXFilePath; - - QDir _tempDir; - QString _originalFBXFilePath; - - QMultiHash> _bakingTextures; QHash _textureNameMatchCount; QHash _remappedTexturePaths; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 3490ca69f5..9e213d1630 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -268,7 +268,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture textureChild = bakedTextureFileName.toLocal8Bit(); - if (!_bakingTextures.contains(urlToTexture)) { + if (!bakingTextures.contains(urlToTexture)) { _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously @@ -325,7 +325,7 @@ 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()); @@ -376,7 +376,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 { @@ -387,10 +387,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(); } @@ -400,7 +400,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(); } @@ -424,7 +424,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 @@ -447,14 +447,14 @@ void ModelBaker::handleAbortedTexture() { TextureBaker* bakedTexture = qobject_cast(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(); } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 955aa1acb8..ad787076ac 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -39,7 +39,7 @@ public: bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL); virtual void setWasAborted(bool wasAborted) override; - + protected: void checkIfTexturesFinished(); @@ -48,6 +48,10 @@ protected: QString originalOutputDir; TextureBakerThreadGetter textureThreadGetter; QUrl modelURL; + QString bakedModelFilePath; + QDir modelTempDir; + QString originalModelFilePath; + QMultiHash> bakingTextures; public slots: virtual void bake() override; @@ -66,10 +70,6 @@ private: QHash _textureNameMatchCount; QHash _remappedTexturePaths; - //QUrl _modelURL; - QMultiHash> _bakingTextures; - //TextureBakerThreadGetter _textureThreadGetter; - //QString _originalOutputDir; bool _pendingErrorEmission{ false }; }; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 5be36b3ff7..c4e8c172bd 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -42,12 +42,12 @@ OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGet } OBJBaker::~OBJBaker() { - if (_tempDir.exists()) { - if (!_tempDir.remove(_originalOBJFilePath)) { - qCWarning(model_baking) << "Failed to remove temporary copy of OBJ file:" << _originalOBJFilePath; + if (modelTempDir.exists()) { + if (!modelTempDir.remove(originalModelFilePath)) { + qCWarning(model_baking) << "Failed to remove temporary copy of OBJ file:" << originalModelFilePath; } - if (!_tempDir.rmdir(".")) { - qCWarning(model_baking) << "Failed to remove temporary directory:" << _tempDir; + if (!modelTempDir.rmdir(".")) { + qCWarning(model_baking) << "Failed to remove temporary directory:" << modelTempDir; } } } @@ -62,11 +62,11 @@ void OBJBaker::bake() { return; } - _tempDir = tempDir; + modelTempDir = tempDir; - _originalOBJFilePath = _tempDir.filePath(modelURL.fileName()); - qDebug() << "Made temporary dir " << _tempDir; - qDebug() << "Origin file path: " << _originalOBJFilePath; + 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); @@ -81,7 +81,7 @@ void OBJBaker::loadOBJ() { // loading the local OBJ QFile localOBJ{ modelURL.toLocalFile() }; - qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << _originalOBJFilePath; + qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << originalModelFilePath; if (!localOBJ.exists()) { handleError("Could not find " + modelURL.toString()); @@ -94,7 +94,7 @@ void OBJBaker::loadOBJ() { localOBJ.copy(originalOutputDir + "/" + modelURL.fileName()); } - localOBJ.copy(_originalOBJFilePath); + localOBJ.copy(originalModelFilePath); // local OBJ is loaded emit signal to trigger its baking emit OBJLoaded(); @@ -124,13 +124,13 @@ void OBJBaker::handleOBJNetworkReply() { qCDebug(model_baking) << "Downloaded" << modelURL; // grab the contents of the reply and make a copy in the output folder - QFile copyOfOriginal(_originalOBJFilePath); + QFile copyOfOriginal(originalModelFilePath); - qDebug(model_baking) << "Writing copy of original obj to" << _originalOBJFilePath << 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 " + _originalOBJFilePath + ")"); + handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + originalModelFilePath + ")"); return; } if (copyOfOriginal.write(requestReply->readAll()) == -1) { @@ -156,9 +156,9 @@ void OBJBaker::handleOBJNetworkReply() { void OBJBaker::bakeOBJ() { // Read the OBJ file - QFile objFile(_originalOBJFilePath); + QFile objFile(originalModelFilePath); if (!objFile.open(QIODevice::ReadOnly)) { - handleError("Error opening " + _originalOBJFilePath + " for reading"); + handleError("Error opening " + originalModelFilePath + " for reading"); return; } @@ -180,20 +180,20 @@ void OBJBaker::bakeOBJ() { auto baseName = fileName.left(fileName.lastIndexOf('.')); auto bakedFilename = baseName + ".baked.fbx"; - _bakedOBJFilePath = bakedOutputDir + "/" + bakedFilename; + bakedModelFilePath = bakedOutputDir + "/" + bakedFilename; QFile bakedFile; - bakedFile.setFileName(_bakedOBJFilePath); + bakedFile.setFileName(bakedModelFilePath); if (!bakedFile.open(QIODevice::WriteOnly)) { - handleError("Error opening " + _bakedOBJFilePath + " for writing"); + handleError("Error opening " + bakedModelFilePath + " for writing"); return; } bakedFile.write(encodedFBX); // Export successful - _outputFiles.push_back(_bakedOBJFilePath); - qCDebug(model_baking) << "Exported" << modelURL << "to" << _bakedOBJFilePath; + _outputFiles.push_back(bakedModelFilePath); + qCDebug(model_baking) << "Exported" << modelURL << "to" << bakedModelFilePath; // Export done emit finished emit finished(); diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 3a3cb63fcb..7b89504a11 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -45,11 +45,6 @@ private slots: private: qlonglong _nodeID = 0; - QString _bakedOBJFilePath; - QDir _tempDir; - QString _originalOBJFilePath; - QMultiHash> _bakingTextures; - qlonglong _geometryID; qlonglong _modelID; std::vector _materialIDs; From 6c553e59237087ba8b03df8d5fc360f44b2e745e Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 19:04:12 -0700 Subject: [PATCH 13/33] moved FBXBaker::abort() to ModelBaker::abort() --- libraries/baking/src/FBXBaker.cpp | 18 +++++++++--------- libraries/baking/src/FBXBaker.h | 2 +- libraries/baking/src/ModelBaker.cpp | 10 ++++++++++ libraries/baking/src/ModelBaker.h | 1 + libraries/baking/src/OBJBaker.cpp | 4 ++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 8df9964d0c..a4341fe57c 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -51,15 +51,15 @@ FBXBaker::~FBXBaker() { } } -void FBXBaker::abort() { - Baker::abort(); - - // tell our underlying TextureBaker instances to abort - // the FBXBaker will wait until all are aborted before emitting its own abort signal - for (auto& textureBaker : bakingTextures) { - textureBaker->abort(); - } -} +//void FBXBaker::abort() { +// Baker::abort(); +// +// // tell our underlying TextureBaker instances to abort +// // the FBXBaker will wait until all are aborted before emitting its own abort signal +// for (auto& textureBaker : bakingTextures) { +// textureBaker->abort(); +// } +//} void FBXBaker::bake() { qDebug() << "FBXBaker" << modelURL << "bake starting"; diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 941c86b703..6d6c2aa90a 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -42,7 +42,7 @@ public: public slots: virtual void bake() override; - virtual void abort() override; + //virtual void abort() override; signals: void sourceCopyReadyToLoad(); diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 9e213d1630..36abce6355 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -41,6 +41,16 @@ ModelBaker::ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThr void ModelBaker::bake() {} +void ModelBaker::abort() { + Baker::abort(); + + // tell our underlying TextureBaker instances to abort + // the FBXBaker will wait until all are aborted before emitting its own abort signal + for (auto& textureBaker : bakingTextures) { + textureBaker->abort(); + } +} + bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback) { if (mesh.wasCompressed) { handleError("Cannot re-bake a file that contains compressed mesh"); diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index ad787076ac..f2d106b3e7 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -55,6 +55,7 @@ protected: public slots: virtual void bake() override; + virtual void abort() override; private slots: void handleBakedTexture(); diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index c4e8c172bd..cf8733a3b2 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -257,7 +257,6 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { } // Generating Texture Node - int count = 0; // iterate through mesh parts and process the associated textures for (int i = 0;i < meshParts.size();i++) { QString material = meshParts[i].materialID; @@ -333,7 +332,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { } // Connect textures to materials - for (int i = 0;i < _mapTextureMaterial.size();i++) { + int mapSize = _mapTextureMaterial.size(); + for (int i = 0;i < mapSize;i++) { FBXNode cNode2; cNode2.name = C_NODE_NAME; propertyString = CONNECTIONS_NODE_PROPERTY_1; From 2fa7c0a07d8b66c7ef82ada9826c4e66eabf7608 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Wed, 25 Oct 2017 19:52:37 -0700 Subject: [PATCH 14/33] Removed unused library --- libraries/baking/src/FBXBaker.cpp | 10 ---------- libraries/baking/src/FBXBaker.h | 1 - libraries/baking/src/ModelBaker.cpp | 3 +-- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index a4341fe57c..5acb8ee1bf 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -51,16 +51,6 @@ FBXBaker::~FBXBaker() { } } -//void FBXBaker::abort() { -// Baker::abort(); -// -// // tell our underlying TextureBaker instances to abort -// // the FBXBaker will wait until all are aborted before emitting its own abort signal -// for (auto& textureBaker : bakingTextures) { -// textureBaker->abort(); -// } -//} - void FBXBaker::bake() { qDebug() << "FBXBaker" << modelURL << "bake starting"; diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 6d6c2aa90a..05dcb1d296 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -42,7 +42,6 @@ public: public slots: virtual void bake() override; - //virtual void abort() override; signals: void sourceCopyReadyToLoad(); diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 36abce6355..531cc31b9f 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -11,7 +11,6 @@ #include "ModelBaker.h" -#include #include #include @@ -45,7 +44,7 @@ void ModelBaker::abort() { Baker::abort(); // tell our underlying TextureBaker instances to abort - // the FBXBaker 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) { textureBaker->abort(); } From 735e641548968d51a15874976aa4b4032669191f Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Thu, 26 Oct 2017 10:48:50 -0700 Subject: [PATCH 15/33] fixed errors with Jenkins build --- libraries/baking/src/OBJBaker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index cf8733a3b2..8739d1d44a 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -332,8 +332,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { } // Connect textures to materials - int mapSize = _mapTextureMaterial.size(); - for (int i = 0;i < mapSize;i++) { + auto mapSize = _mapTextureMaterial.size(); + for (size_t i = 0;i < mapSize;i++) { FBXNode cNode2; cNode2.name = C_NODE_NAME; propertyString = CONNECTIONS_NODE_PROPERTY_1; From 1092c09e8bb5b60065f262fd5794250fecc79595 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Thu, 26 Oct 2017 11:40:26 -0700 Subject: [PATCH 16/33] changed variable names --- libraries/baking/src/FBXBaker.h | 1 - libraries/baking/src/ModelBaker.cpp | 12 ++++++------ libraries/baking/src/ModelBaker.h | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 05dcb1d296..797be14011 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -59,7 +59,6 @@ private: void rewriteAndBakeSceneModels(); void rewriteAndBakeSceneTextures(); void exportScene(); - void removeEmbeddedMediaFolder(); FBXNode _rootNode; FBXGeometry* _geometry; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 531cc31b9f..19e15c8377 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -28,12 +28,12 @@ #pragma warning( pop ) #endif -ModelBaker::ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir) : - modelURL(modelURL), - textureThreadGetter(textureThreadGetter), - bakedOutputDir(bakedOutputDir), - originalOutputDir(originalOutputDir) +ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter, + const QString& bakedOutputDirectory, const QString& originalOutputDirectory) : + modelURL(inputModelURL), + textureThreadGetter(inputTextureThreadGetter), + bakedOutputDir(bakedOutputDirectory), + originalOutputDir(originalOutputDirectory) { } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index f2d106b3e7..bb1b5e7c11 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -34,8 +34,8 @@ class ModelBaker : public Baker{ Q_OBJECT public: - ModelBaker(const QUrl& modelURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir); + ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter, + const QString& bakedOutputDirectory, const QString& originalOutputDirectory); bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL); virtual void setWasAborted(bool wasAborted) override; From d8b0a6360e2360296ee01be0f1aceb3912155578 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Thu, 26 Oct 2017 13:11:59 -0700 Subject: [PATCH 17/33] Fix for -Wreorder warning --- libraries/baking/src/ModelBaker.cpp | 2 +- libraries/baking/src/ModelBaker.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 19e15c8377..07cb722f59 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -226,7 +226,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTextureTypeCallback textureTypeCallback) { static QByteArray textureChild; QByteArray textureContent = ""; - image::TextureUsage::Type textureType; + image::TextureUsage::Type textureType = image::TextureUsage::Type::DEFAULT_TEXTURE; if (textureTypeCallback) { textureType = textureTypeCallback(); diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index bb1b5e7c11..ad56a84343 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -44,10 +44,10 @@ protected: void checkIfTexturesFinished(); QHash textureContentMap; + QUrl modelURL; + TextureBakerThreadGetter textureThreadGetter; QString bakedOutputDir; QString originalOutputDir; - TextureBakerThreadGetter textureThreadGetter; - QUrl modelURL; QString bakedModelFilePath; QDir modelTempDir; QString originalModelFilePath; From 730202b7fc38a352caf7a7cdee659d748df180f6 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Thu, 26 Oct 2017 14:22:23 -0700 Subject: [PATCH 18/33] Refactored ModelBaker --- libraries/baking/src/ModelBaker.cpp | 104 ++++++++++++++-------------- libraries/baking/src/ModelBaker.h | 1 - 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 07cb722f59..ba207b1cd3 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -38,8 +38,6 @@ ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter input } -void ModelBaker::bake() {} - void ModelBaker::abort() { Baker::abort(); @@ -288,38 +286,6 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture return &textureChild; } -QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded) { - QUrl urlToTexture; - - // use QFileInfo to easily split up the existing texture filename into its components - auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/")); - - if (isEmbedded) { - urlToTexture = modelURL.toString() + "/" + apparentRelativePath.filePath(); - } else { - if (textureFileInfo.exists() && textureFileInfo.isFile()) { - // set the texture URL to the local texture that we have confirmed exists - urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); - } else { - // external texture that we'll need to download or find - - // 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()) { - // 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()); - } - } - } - - return urlToTexture; -} - void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { @@ -416,6 +382,57 @@ void ModelBaker::handleBakedTexture() { } } +void ModelBaker::handleAbortedTexture() { + // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore + TextureBaker* bakedTexture = qobject_cast(sender()); + + if (bakedTexture) { + 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) { + bakingTexture->abort(); + } + + checkIfTexturesFinished(); +} + +QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded) { + QUrl urlToTexture; + + // use QFileInfo to easily split up the existing texture filename into its components + auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/")); + + if (isEmbedded) { + urlToTexture = modelURL.toString() + "/" + apparentRelativePath.filePath(); + } else { + if (textureFileInfo.exists() && textureFileInfo.isFile()) { + // set the texture URL to the local texture that we have confirmed exists + urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); + } else { + // external texture that we'll need to download or find + + // 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()) { + // 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()); + } + } + } + + return urlToTexture; +} + QString ModelBaker::texturePathRelativeToModel(QUrl modelURL, QUrl textureURL) { auto modelPath = modelURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); @@ -451,25 +468,6 @@ void ModelBaker::checkIfTexturesFinished() { } } -void ModelBaker::handleAbortedTexture() { - // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore - TextureBaker* bakedTexture = qobject_cast(sender()); - - if (bakedTexture) { - 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) { - bakingTexture->abort(); - } - - checkIfTexturesFinished(); -} - QString ModelBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { // first make sure we have a unique base name for this texture // in case another texture referenced by this model has the same base name diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index ad56a84343..05ed72a364 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -54,7 +54,6 @@ protected: QMultiHash> bakingTextures; public slots: - virtual void bake() override; virtual void abort() override; private slots: From dd2d3d97b4da522330edba637379d1350d82e628 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 16 Nov 2017 16:32:11 -0800 Subject: [PATCH 19/33] Fix coding guideline violations in *Baker classes --- libraries/baking/src/FBXBaker.cpp | 100 +++++++------------ libraries/baking/src/FBXBaker.h | 5 +- libraries/baking/src/ModelBaker.cpp | 81 +++++++++------ libraries/baking/src/ModelBaker.h | 22 ++--- libraries/baking/src/OBJBaker.cpp | 148 ++++++++++++---------------- libraries/baking/src/OBJBaker.h | 1 - 6 files changed, 165 insertions(+), 192 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 5acb8ee1bf..f7b6511d8f 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -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(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; } diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 797be14011..31bbd7ba0d 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -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; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index ba207b1cd3..7c8648b5f7 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -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(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; } } } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 05ed72a364..3133e962ec 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -30,12 +30,13 @@ using TextureBakerThreadGetter = std::function; using getMaterialIDCallback = std::function ; using getTextureTypeCallback = std::function; -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 textureContentMap; - QUrl modelURL; - TextureBakerThreadGetter textureThreadGetter; - QString bakedOutputDir; - QString originalOutputDir; - QString bakedModelFilePath; - QDir modelTempDir; - QString originalModelFilePath; - QMultiHash> bakingTextures; + QHash _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> _bakingTextures; QHash _textureNameMatchCount; QHash _remappedTexturePaths; bool _pendingErrorEmission{ false }; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 8739d1d44a..ca919b1011 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -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(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(_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 stringProperties{ "UnitScaleFactor", "double", "Number", "" }; - std::vector numericProperties{ UNIT_SCALE_FACTOR }; + std::vector stringProperties { "UnitScaleFactor", "double", "Number", "" }; + std::vector 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 stringProperties{ "DiffuseColor", "Color", "", "A" }; - std::vector numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] }; + std::vector stringProperties { "DiffuseColor", "Color", "", "A" }; + std::vector 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 diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 7b89504a11..a620afe148 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -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); From 6050b4d85c96920ed15133c3564dc21cbf4f9fcb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Nov 2017 09:05:22 -0800 Subject: [PATCH 20/33] Cleanup ObjBaker and remove setPropertiesList --- libraries/baking/src/OBJBaker.cpp | 237 +++++++++++++++--------------- 1 file changed, 117 insertions(+), 120 deletions(-) diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index ca919b1011..6e75070420 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -129,7 +129,6 @@ void OBJBaker::handleOBJNetworkReply() { } } - void OBJBaker::bakeOBJ() { // Read the OBJ file QFile objFile(_originalModelFilePath); @@ -188,9 +187,16 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Setting the tree hierarchy: GlobalSettings -> Properties70 -> P -> Properties FBXNode properties70Node; properties70Node.name = PROPERTIES70_NODE_NAME; + FBXNode pNode; - pNode.name = P_NODE_NAME; - setNodeProperties(pNode); + { + pNode.name = P_NODE_NAME; + pNode.properties.append({ + "UnitScaleFactor", "double", "Number", "", + UNIT_SCALE_FACTOR + }); + } + properties70Node.children = { pNode }; globalSettingsNode.children = { properties70Node }; @@ -200,7 +206,14 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Generating Object node's child - Geometry node FBXNode geometryNode; geometryNode.name = GEOMETRY_NODE_NAME; - setNodeProperties(geometryNode); + { + _geometryID = _nodeID; + geometryNode.properties = { + _nodeID++, + GEOMETRY_NODE_NAME, + MESH + }; + } // Compress the mesh information and store in dracoNode bool hasDeformers = false; // No concept of deformers for an OBJ @@ -211,7 +224,14 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Generating Object node's child - Model node FBXNode modelNode; modelNode.name = MODEL_NODE_NAME; - setNodeProperties(modelNode); + { + _modelID = _nodeID++; + modelNode.properties = { + _nodeID, + MODEL_NODE_NAME, + MESH + }; + } _objectNode.children = { geometryNode, modelNode }; @@ -222,7 +242,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { materialNode.name = MATERIAL_NODE_NAME; if (geometry.materials.size() == 1) { // case when no material information is provided, OBJReader considers it as a single default material - foreach(QString materialID, geometry.materials.keys()) { + for (auto& materialID : geometry.materials.keys()) { setMaterialNodeProperties(materialNode, materialID, geometry); } } else { @@ -234,7 +254,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Generating Texture Node // iterate through mesh parts and process the associated textures - for (int i = 0; i < meshParts.size(); i++) { + auto size = meshParts.size(); + for (int i = 0; i < size; i++) { QString material = meshParts[i].materialID; FBXMaterial currentMaterial = geometry.materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { @@ -242,20 +263,24 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { _mapTextureMaterial.push_back(QPair(_textureID, i)); FBXNode textureNode; - textureNode.name = TEXTURE_NODE_NAME; - QVariant textureProperty(_nodeID++); - textureNode.properties = { textureProperty }; + { + textureNode.name = TEXTURE_NODE_NAME; + textureNode.properties = { _nodeID++ }; + } // Texture node child - TextureName node FBXNode textureNameNode; - textureNameNode.name = TEXTURENAME_NODE_NAME; - QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; - textureProperty = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - textureNameNode.properties = { textureProperty }; + { + textureNameNode.name = TEXTURENAME_NODE_NAME; + QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; + textureNameNode.properties = { propertyString }; + } // Texture node child - Relative Filename node FBXNode relativeFilenameNode; - relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME; + { + relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME; + } QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; @@ -266,13 +291,11 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback); - if (textureFile) { - textureProperty = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); - } else { + if (!textureFile) { // Baking failed return return; } - relativeFilenameNode.properties = { textureProperty }; + relativeFilenameNode.properties = { *textureFile }; textureNode.children = { textureNameNode, relativeFilenameNode }; @@ -287,23 +310,36 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // connect Geometry to Model FBXNode cNode; cNode.name = C_NODE_NAME; - QByteArray propertyString(CONNECTIONS_NODE_PROPERTY); - QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - qlonglong childID = _geometryID; - QVariant property1(childID); - qlonglong parentID = _modelID; - QVariant property2(parentID); - cNode.properties = { property0, property1, property2 }; + + cNode.properties = { + CONNECTIONS_NODE_PROPERTY, + _geometryID, + _modelID + }; + connectionsNode.children = { cNode }; // connect all materials to model - for (int i = 0; i < geometry.materials.size(); i++) { + for (auto& materialID : _materialIDs) { FBXNode cNode1; cNode1.name = C_NODE_NAME; - property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - property1 = _materialIDs[i]; - property2 = _modelID; - cNode1.properties = { property0, property1, property2 }; + cNode1.properties = { + CONNECTIONS_NODE_PROPERTY, + materialID, + _modelID + }; + connectionsNode.children.append(cNode1); + } + for (int i = 0; i < geometry.materials.size(); i++) { + continue; + FBXNode cNode1; + cNode1.name = C_NODE_NAME; + cNode1.properties = { + CONNECTIONS_NODE_PROPERTY, + _materialIDs[i], + _modelID + }; + connectionsNode.children.append(cNode1); } @@ -312,25 +348,25 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { for (size_t i = 0; i < mapSize; i++) { FBXNode cNode2; cNode2.name = C_NODE_NAME; - propertyString = CONNECTIONS_NODE_PROPERTY_1; - property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - property1 = _mapTextureMaterial[i].first; - int matID = _mapTextureMaterial[i].second; - property2 = _materialIDs[matID]; - propertyString = "AmbientFactor"; - QVariant property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - cNode2.properties = { property0, property1, property2, property3 }; + auto& texMat = _mapTextureMaterial[i]; + cNode2.properties = { + CONNECTIONS_NODE_PROPERTY_1, + texMat.first, + _materialIDs[texMat.second], + "AmbientFactor" + }; + connectionsNode.children.append(cNode2); FBXNode cNode3; cNode3.name = C_NODE_NAME; - propertyString = CONNECTIONS_NODE_PROPERTY_1; - property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - property1 = _mapTextureMaterial[i].first; - property2 = _materialIDs[matID]; - propertyString = "DiffuseColor"; - property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - cNode3.properties = { property0, property1, property2, property3 }; + cNode3.properties = { + CONNECTIONS_NODE_PROPERTY_1, + texMat.first, + _materialIDs[texMat.second], + "DiffuseColor" + }; + connectionsNode.children.append(cNode3); } @@ -338,44 +374,15 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { rootNode.children = { globalSettingsNode, _objectNode, connectionsNode }; } -// Set properties for P Node and Sub-Object nodes -void OBJBaker::setNodeProperties(FBXNode& parentNode) { - if (parentNode.name == P_NODE_NAME) { - std::vector stringProperties { "UnitScaleFactor", "double", "Number", "" }; - std::vector numericProperties { UNIT_SCALE_FACTOR }; - - setPropertiesList(stringProperties, numericProperties, parentNode.properties); - } else if (parentNode.name == GEOMETRY_NODE_NAME) { - _geometryID = _nodeID; - QVariant property0(_nodeID++); - QByteArray propertyString(GEOMETRY_NODE_NAME); - QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = MESH; - QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - parentNode.properties = { property0, property1, property2 }; - } else if (parentNode.name == MODEL_NODE_NAME) { - _modelID = _nodeID; - QVariant property0(_nodeID++); - QByteArray propertyString(MODEL_NODE_NAME); - QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = MESH; - QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - parentNode.properties = { property0, property1, property2 }; - } -} - // Set properties for material nodes void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) { - _materialIDs.push_back(_nodeID); - QVariant property0(_nodeID++); - QByteArray propertyString(material.toLatin1()); - QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = MESH; - QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - materialNode.properties = { property0, property1, property2 }; + auto materialID = _nodeID++; + _materialIDs.push_back(materialID); + materialNode.properties = { + materialID, + material, + MESH + }; FBXMaterial currentMaterial = geometry.materials[material]; @@ -385,57 +392,47 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material // Set diffuseColor FBXNode pNodeDiffuseColor; - pNodeDiffuseColor.name = P_NODE_NAME; - - std::vector stringProperties { "DiffuseColor", "Color", "", "A" }; - std::vector numericProperties { currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] }; - setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties); - + { + pNodeDiffuseColor.name = P_NODE_NAME; + pNodeDiffuseColor.properties.append({ + "DiffuseColor", "Color", "", "A", + currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] + }); + } properties70Node.children.append(pNodeDiffuseColor); // Set specularColor FBXNode pNodeSpecularColor; - pNodeSpecularColor.name = P_NODE_NAME; - - stringProperties = { "SpecularColor", "Color", "", "A" }; - numericProperties = { currentMaterial.specularColor[0], currentMaterial.specularColor[1], currentMaterial.specularColor[2] }; - setPropertiesList(stringProperties, numericProperties, pNodeSpecularColor.properties); - + { + pNodeSpecularColor.name = P_NODE_NAME; + pNodeSpecularColor.properties.append({ + "SpecularColor", "Color", "", "A", + currentMaterial.specularColor[0], currentMaterial.specularColor[1], currentMaterial.specularColor[2] + }); + } properties70Node.children.append(pNodeSpecularColor); // Set Shininess FBXNode pNodeShininess; - pNodeShininess.name = P_NODE_NAME; - - stringProperties = { "Shininess", "Number", "", "A" }; - numericProperties = { currentMaterial.shininess }; - setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties); - + { + pNodeShininess.name = P_NODE_NAME; + pNodeShininess.properties.append({ + "Shininess", "Number", "", "A", + currentMaterial.shininess + }); + } properties70Node.children.append(pNodeShininess); // Set Opacity FBXNode pNodeOpacity; - pNodeOpacity.name = P_NODE_NAME; - - stringProperties = { "Opacity", "Number", "", "A" }; - numericProperties = { currentMaterial.opacity }; - setPropertiesList(stringProperties, numericProperties, pNodeOpacity.properties); - + { + pNodeOpacity.name = P_NODE_NAME; + pNodeOpacity.properties.append({ + "Opacity", "Number", "", "A", + currentMaterial.opacity + }); + } properties70Node.children.append(pNodeOpacity); materialNode.children.append(properties70Node); } - -// Bundle various String and numerical type properties into a single QVariantList -template -void OBJBaker::setPropertiesList(std::vector& stringProperties, std::vector& numericProperties, QVariantList& propertiesList) { - foreach(auto stringProperty, stringProperties) { - auto propertyValue = QVariant::fromValue(QByteArray(stringProperty.data(), (int)stringProperty.size())); - propertiesList.append(propertyValue); - } - - foreach(auto numericProperty, numericProperties) { - QVariant propertyValue(numericProperty); - propertiesList.append(propertyValue); - } -} From 7026337f24150a31081d880bc0ebbcf616a047c8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Nov 2017 09:05:37 -0800 Subject: [PATCH 21/33] Fix broken string serialization in FBXWriter --- libraries/fbx/src/FBXWriter.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/libraries/fbx/src/FBXWriter.cpp b/libraries/fbx/src/FBXWriter.cpp index 5029b489bc..511f253193 100644 --- a/libraries/fbx/src/FBXWriter.cpp +++ b/libraries/fbx/src/FBXWriter.cpp @@ -161,23 +161,19 @@ void FBXWriter::encodeFBXProperty(QDataStream& out, const QVariant& prop) { case QMetaType::QString: { auto bytes = prop.toString().toUtf8(); - out << 'S'; - out << bytes.length(); - out << bytes; + out.device()->write("S", 1); out << (int32_t)bytes.size(); out.writeRawData(bytes, bytes.size()); break; } - case QMetaType::QByteArray: - { - auto bytes = prop.toByteArray(); - out.device()->write("S", 1); - out << (int32_t)bytes.size(); - out.writeRawData(bytes, bytes.size()); - break; - } - + { + auto bytes = prop.toByteArray(); + out.device()->write("S", 1); + out << (int32_t)bytes.size(); + out.writeRawData(bytes, bytes.size()); + break; + } default: { if (prop.canConvert>()) { From 5c522d556bd90542ddbcc4e1dcd4432ccdacd7be Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Nov 2017 09:43:22 -0800 Subject: [PATCH 22/33] Cleanup connection generation in OBJBaker --- libraries/baking/src/OBJBaker.cpp | 44 +++++++++---------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 6e75070420..88d0c29c18 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -310,64 +310,46 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // connect Geometry to Model FBXNode cNode; cNode.name = C_NODE_NAME; - cNode.properties = { CONNECTIONS_NODE_PROPERTY, _geometryID, _modelID }; - connectionsNode.children = { cNode }; // connect all materials to model for (auto& materialID : _materialIDs) { - FBXNode cNode1; - cNode1.name = C_NODE_NAME; - cNode1.properties = { + FBXNode cNode; + cNode.name = C_NODE_NAME; + cNode.properties = { CONNECTIONS_NODE_PROPERTY, materialID, _modelID }; - connectionsNode.children.append(cNode1); - } - for (int i = 0; i < geometry.materials.size(); i++) { - continue; - FBXNode cNode1; - cNode1.name = C_NODE_NAME; - cNode1.properties = { - CONNECTIONS_NODE_PROPERTY, - _materialIDs[i], - _modelID - }; - - connectionsNode.children.append(cNode1); + connectionsNode.children.append(cNode); } // Connect textures to materials - auto mapSize = _mapTextureMaterial.size(); - for (size_t i = 0; i < mapSize; i++) { - FBXNode cNode2; - cNode2.name = C_NODE_NAME; - auto& texMat = _mapTextureMaterial[i]; - cNode2.properties = { + for (auto& texMat : _mapTextureMaterial) { + FBXNode cAmbientNode; + cAmbientNode.name = C_NODE_NAME; + cAmbientNode.properties = { CONNECTIONS_NODE_PROPERTY_1, texMat.first, _materialIDs[texMat.second], "AmbientFactor" }; + connectionsNode.children.append(cAmbientNode); - connectionsNode.children.append(cNode2); - - FBXNode cNode3; - cNode3.name = C_NODE_NAME; - cNode3.properties = { + FBXNode cDiffuseNode; + cDiffuseNode.name = C_NODE_NAME; + cDiffuseNode.properties = { CONNECTIONS_NODE_PROPERTY_1, texMat.first, _materialIDs[texMat.second], "DiffuseColor" }; - - connectionsNode.children.append(cNode3); + connectionsNode.children.append(cDiffuseNode); } // Make all generated nodes children of rootNode From 8c9c069a5ce25d54f229f162234bddd5ed7006f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Nov 2017 11:50:46 -0800 Subject: [PATCH 23/33] Update OBJ/FBX bakers to inherit parent ctor --- libraries/baking/src/FBXBaker.cpp | 7 ------- libraries/baking/src/FBXBaker.h | 3 +-- libraries/baking/src/ModelBaker.h | 8 ++++---- libraries/baking/src/OBJBaker.cpp | 7 ------- libraries/baking/src/OBJBaker.h | 13 +++++-------- 5 files changed, 10 insertions(+), 28 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index f7b6511d8f..26b927452e 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -33,13 +33,6 @@ #include "FBXBaker.h" -FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir) : - ModelBaker(fbxURL, textureThreadGetter, bakedOutputDir, originalOutputDir) -{ - -} - void FBXBaker::bake() { qDebug() << "FBXBaker" << _modelURL << "bake starting"; diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 31bbd7ba0d..0a3b80fde9 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -33,8 +33,7 @@ using TextureBakerThreadGetter = std::function; class FBXBaker : public ModelBaker { Q_OBJECT public: - FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir = ""); + using ModelBaker::ModelBaker; QUrl getFBXUrl() const { return _modelURL; } QString getBakedFBXFilePath() const { return _bakedModelFilePath; } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 3133e962ec..5949e12774 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -35,12 +35,15 @@ class ModelBaker : public Baker { public: 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); QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL); virtual void setWasAborted(bool wasAborted) override; +public slots: + virtual void abort() override; + protected: void checkIfTexturesFinished(); @@ -52,9 +55,6 @@ protected: QDir _modelTempDir; QString _originalModelFilePath; -public slots: - virtual void abort() override; - private slots: void handleBakedTexture(); void handleAbortedTexture(); diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 88d0c29c18..f84e2abd29 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -34,13 +34,6 @@ const QByteArray CONNECTIONS_NODE_PROPERTY = "OO"; const QByteArray CONNECTIONS_NODE_PROPERTY_1 = "OP"; const QByteArray MESH = "Mesh"; -OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir) : - ModelBaker(objURL, textureThreadGetter, bakedOutputDir, originalOutputDir) -{ - -} - void OBJBaker::bake() { qDebug() << "OBJBaker" << _modelURL << "bake starting"; diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index a620afe148..4c41fb5db4 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -23,14 +23,7 @@ using TextureBakerThreadGetter = std::function; class OBJBaker : public ModelBaker { Q_OBJECT public: - OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, - const QString& bakedOutputDir, const QString& originalOutputDir = ""); - void loadOBJ(); - void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry); - void setNodeProperties(FBXNode& parentNode); - void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry); - template - void setPropertiesList(std::vector& stringProperties, std::vector& numericProperties, QVariantList& propertiesList); + using ModelBaker::ModelBaker; public slots: virtual void bake() override; @@ -43,6 +36,10 @@ private slots: void handleOBJNetworkReply(); private: + void loadOBJ(); + void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry); + void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry); + qlonglong _nodeID = 0; qlonglong _geometryID; qlonglong _modelID; From 57b943ae98d6625a030e5eb1e552430ad84a3d12 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Nov 2017 13:51:44 -0800 Subject: [PATCH 24/33] Fix initialization order in ModelBaker --- libraries/baking/src/ModelBaker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 7c8648b5f7..1c3040dd24 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -31,9 +31,9 @@ ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter, const QString& bakedOutputDirectory, const QString& originalOutputDirectory) : _modelURL(inputModelURL), - _textureThreadGetter(inputTextureThreadGetter), _bakedOutputDir(bakedOutputDirectory), - _originalOutputDir(originalOutputDirectory) + _originalOutputDir(originalOutputDirectory), + _textureThreadGetter(inputTextureThreadGetter) { auto tempDir = PathUtils::generateTemporaryDir(); From 70c35f84b5c5fc8a3414c64ef53709903241832b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Dec 2017 10:29:26 -0800 Subject: [PATCH 25/33] Update baker library with many style improvements --- libraries/baking/src/FBXBaker.cpp | 25 ++++++----- libraries/baking/src/FBXBaker.h | 3 -- libraries/baking/src/ModelBaker.cpp | 35 +++++++-------- libraries/baking/src/ModelBaker.h | 10 +++-- libraries/baking/src/OBJBaker.cpp | 43 ++++++------------- libraries/baking/src/OBJBaker.h | 7 ++- libraries/fbx/src/OBJReader.cpp | 6 +-- libraries/fbx/src/OBJReader.h | 2 +- .../src/model-networking/ModelCache.cpp | 4 +- tools/oven/src/DomainBaker.cpp | 10 ++--- tools/oven/src/ui/BakeWidget.cpp | 2 +- tools/oven/src/ui/ModelBakeWidget.cpp | 40 ++++++++--------- tools/oven/src/ui/ModelBakeWidget.h | 3 -- tools/oven/src/ui/OvenMainWindow.cpp | 2 +- tools/vhacd-util/src/VHACDUtil.cpp | 5 +-- 15 files changed, 84 insertions(+), 113 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 26b927452e..035903c6cb 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -223,11 +223,13 @@ void FBXBaker::rewriteAndBakeSceneModels() { auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); // Callback to get MaterialID - getMaterialIDCallback materialIDcallback = [=](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + GetMaterialIDCallback materialIDcallback = [&extractedMesh](int partIndex) { + return extractedMesh.partMaterialTextures[partIndex].first; + }; // Compress mesh information and store in dracoMeshNode FBXNode dracoMeshNode; - bool success = this->compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback); + bool success = compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback); // if bake fails - return, if there were errors and continue, if there were warnings. if (!success) { @@ -314,23 +316,20 @@ void FBXBaker::rewriteAndBakeSceneTextures() { for (FBXNode& textureChild : object->children) { if (textureChild.name == "RelativeFilename") { - QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() }; + QString fbxTextureFileName { textureChild.properties.at(0).toString() }; // Callback to get texture type - getTextureTypeCallback textureTypeCallback = [=]() { - // grab the ID for this texture so we can figure out the - // texture type from the loaded materials - auto textureID{ object->properties[0].toByteArray() }; - auto textureType = textureTypes[textureID]; - return textureType; - }; + // grab the ID for this texture so we can figure out the + // texture type from the loaded materials + auto textureID { object->properties[0].toString() }; + auto textureType = textureTypes[textureID]; // Compress the texture information and return the new filename to be added into the FBX scene - QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, textureTypeCallback); + auto bakedTextureFile = compressTexture(fbxTextureFileName, textureType); // If no errors or warnings have occurred during texture compression add the filename to the FBX scene - if (bakedTextureFile) { - textureChild.properties[0] = *bakedTextureFile; + if (!bakedTextureFile.isNull()) { + textureChild.properties[0] = bakedTextureFile; } else { // if bake fails - return, if there were errors and continue, if there were warnings. if (hasErrors()) { diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 0a3b80fde9..2888a60f73 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -35,9 +35,6 @@ class FBXBaker : public ModelBaker { public: using ModelBaker::ModelBaker; - QUrl getFBXUrl() const { return _modelURL; } - QString getBakedFBXFilePath() const { return _bakedModelFilePath; } - public slots: virtual void bake() override; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 1c3040dd24..5d04c17688 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -71,7 +71,7 @@ void ModelBaker::abort() { } } -bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback) { +bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback) { if (mesh.wasCompressed) { handleError("Cannot re-bake a file that contains compressed mesh"); return false; @@ -106,12 +106,12 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes bool hasPerFaceMaterials = (materialIDCallback) ? (mesh.parts.size() > 1 || materialIDCallback(0) != 0 ) : true; bool needsOriginalIndices{ hasDeformers }; - int normalsAttributeID{ -1 }; - int colorsAttributeID{ -1 }; - int texCoordsAttributeID{ -1 }; - int texCoords1AttributeID{ -1 }; - int faceMaterialAttributeID{ -1 }; - int originalIndexAttributeID{ -1 }; + int normalsAttributeID { -1 }; + int colorsAttributeID { -1 }; + int texCoordsAttributeID { -1 }; + int texCoords1AttributeID { -1 }; + int faceMaterialAttributeID { -1 }; + int originalIndexAttributeID { -1 }; const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION, 3, draco::DT_FLOAT32); @@ -244,14 +244,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes return true; } -QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTextureTypeCallback textureTypeCallback) { - static QByteArray textureChild; - QByteArray textureContent = ""; - image::TextureUsage::Type textureType = image::TextureUsage::Type::DEFAULT_TEXTURE; - - if (textureTypeCallback) { - textureType = textureTypeCallback(); - } +QString ModelBaker::compressTexture(QString modelTextureFileName, image::TextureUsage::Type textureType) { QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; @@ -259,18 +252,20 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture // re-baking a model that already references baked textures // this is an error - return from here handleError("Cannot re-bake a file that already references compressed textures"); - return nullptr; + return QString::null; } if (!TextureBaker::getSupportedFormats().contains(modelTextureFileInfo.suffix())) { // this is a texture format we don't bake, skip it handleWarning(modelTextureFileName + " is not a bakeable texture format"); - return nullptr; + return QString::null; } // make sure this texture points to something and isn't one we've already re-mapped + QString textureChild { QString::null }; if (!modelTextureFileInfo.filePath().isEmpty()) { // check if this was an embedded texture that we already have in-memory content for + QByteArray textureContent; // figure out the URL to this texture, embedded or external if (!modelTextureFileInfo.filePath().isEmpty()) { @@ -296,7 +291,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture _bakedOutputDir + "/" + bakedTextureFileName }; - textureChild = bakedTextureFileName.toLocal8Bit(); + textureChild = bakedTextureFileName; if (!_bakingTextures.contains(urlToTexture)) { _outputFiles.push_back(bakedTextureFilePath); @@ -306,11 +301,11 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture } } - return &textureChild; + return textureChild; } void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { + const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { // start a bake for this texture and add it to our list to keep track of QSharedPointer bakingTexture{ diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 5949e12774..944b9b8f2a 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -27,8 +27,7 @@ #include using TextureBakerThreadGetter = std::function; -using getMaterialIDCallback = std::function ; -using getTextureTypeCallback = std::function; +using GetMaterialIDCallback = std::function ; class ModelBaker : public Baker { Q_OBJECT @@ -37,10 +36,13 @@ 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); + bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback = nullptr); + QString compressTexture(QString textureFileName, image::TextureUsage::Type = image::TextureUsage::Type::DEFAULT_TEXTURE); virtual void setWasAborted(bool wasAborted) override; + QUrl getModelURL() const { return _modelURL; } + QString getBakedModelFilePath() const { return _bakedModelFilePath; } + public slots: virtual void abort() override; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index f84e2abd29..c4ca3485de 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -134,7 +134,7 @@ 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); + auto geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL); // Write OBJ Data as FBX tree nodes FBXNode rootNode; @@ -211,7 +211,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Compress the mesh information and store in dracoNode bool hasDeformers = false; // No concept of deformers for an OBJ FBXNode dracoNode; - this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode); + compressMesh(geometry.meshes[0], hasDeformers, dracoNode); geometryNode.children.append(dracoNode); // Generating Object node's child - Model node @@ -219,11 +219,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { modelNode.name = MODEL_NODE_NAME; { _modelID = _nodeID++; - modelNode.properties = { - _nodeID, - MODEL_NODE_NAME, - MESH - }; + modelNode.properties = { _nodeID, MODEL_NODE_NAME, MESH }; } _objectNode.children = { geometryNode, modelNode }; @@ -253,7 +249,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { FBXMaterial currentMaterial = geometry.materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { _textureID = _nodeID; - _mapTextureMaterial.push_back(QPair(_textureID, i)); + _mapTextureMaterial.emplace_back(_textureID, i); FBXNode textureNode; { @@ -277,18 +273,15 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { 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; - }; + auto textureType = (!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) { + auto textureFile = compressTexture(textureFileName, textureType); + if (textureFile.isNull()) { // Baking failed return return; } - relativeFilenameNode.properties = { *textureFile }; + relativeFilenameNode.properties = { textureFile }; textureNode.children = { textureNameNode, relativeFilenameNode }; @@ -303,27 +296,19 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // connect Geometry to Model FBXNode cNode; cNode.name = C_NODE_NAME; - cNode.properties = { - CONNECTIONS_NODE_PROPERTY, - _geometryID, - _modelID - }; + cNode.properties = { CONNECTIONS_NODE_PROPERTY, _geometryID, _modelID }; connectionsNode.children = { cNode }; // connect all materials to model for (auto& materialID : _materialIDs) { FBXNode cNode; cNode.name = C_NODE_NAME; - cNode.properties = { - CONNECTIONS_NODE_PROPERTY, - materialID, - _modelID - }; + cNode.properties = { CONNECTIONS_NODE_PROPERTY, materialID, _modelID }; connectionsNode.children.append(cNode); } // Connect textures to materials - for (auto& texMat : _mapTextureMaterial) { + for (const auto& texMat : _mapTextureMaterial) { FBXNode cAmbientNode; cAmbientNode.name = C_NODE_NAME; cAmbientNode.properties = { @@ -353,11 +338,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) { auto materialID = _nodeID++; _materialIDs.push_back(materialID); - materialNode.properties = { - materialID, - material, - MESH - }; + materialNode.properties = { materialID, material, MESH }; FBXMaterial currentMaterial = geometry.materials[material]; diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 4c41fb5db4..2e0d76e954 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -20,6 +20,9 @@ using TextureBakerThreadGetter = std::function; +using TextureID = int64_t; +using MaterialID = int64_t; + class OBJBaker : public ModelBaker { Q_OBJECT public: @@ -43,9 +46,9 @@ private: qlonglong _nodeID = 0; qlonglong _geometryID; qlonglong _modelID; - std::vector _materialIDs; + std::vector _materialIDs; qlonglong _textureID; - std::vector> _mapTextureMaterial; + std::vector> _mapTextureMaterial; FBXNode _objectNode; }; #endif // hifi_OBJBaker_h diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index e0c2efd72e..7fd2d39931 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -490,13 +490,13 @@ done: } -FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) { +FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); QBuffer buffer { &model }; buffer.open(QIODevice::ReadOnly); - FBXGeometry* geometryPtr = new FBXGeometry(); - FBXGeometry& geometry = *geometryPtr; + auto geometryPtr { std::make_shared() }; + FBXGeometry& geometry { *geometryPtr }; OBJTokenizer tokenizer { &buffer }; float scaleGuess = 1.0f; diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index fb250833cf..7fe71892f6 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -75,7 +75,7 @@ public: QString currentMaterialName; QHash materials; - FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl()); + FBXGeometry::Pointer readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl()); private: QUrl _url; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b62ad7b366..2ed301b192 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -186,11 +186,11 @@ void GeometryReader::run() { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); + fbxGeometry = OBJReader().readOBJ(_data, _mapping, _combineParts, _url); } else if (_url.path().toLower().endsWith(".obj.gz")) { QByteArray uncompressedData; if (gunzip(_data, uncompressedData)){ - fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); + fbxGeometry = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url); } else { throw QString("failed to decompress .obj.gz" ); } diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index 535d9a49a9..c5573f8074 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -304,11 +304,11 @@ void DomainBaker::handleFinishedModelBaker() { if (baker) { if (!baker->hasErrors()) { // this FBXBaker is done and everything went according to plan - qDebug() << "Re-writing entity references to" << baker->getFBXUrl(); + qDebug() << "Re-writing entity references to" << baker->getModelURL(); // enumerate the QJsonRef values for the URL of this FBX from our multi hash of // entity objects needing a URL re-write - for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getFBXUrl())) { + for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getModelURL())) { // convert the entity QJsonValueRef to a QJsonObject so we can modify its URL auto entity = entityValue.toObject(); @@ -317,7 +317,7 @@ void DomainBaker::handleFinishedModelBaker() { QUrl oldModelURL { entity[ENTITY_MODEL_URL_KEY].toString() }; // setup a new URL using the prefix we were passed - auto relativeFBXFilePath = baker->getBakedFBXFilePath().remove(_contentOutputPath); + auto relativeFBXFilePath = baker->getBakedModelFilePath().remove(_contentOutputPath); if (relativeFBXFilePath.startsWith("/")) { relativeFBXFilePath = relativeFBXFilePath.right(relativeFBXFilePath.length() - 1); } @@ -370,10 +370,10 @@ void DomainBaker::handleFinishedModelBaker() { } // remove the baked URL from the multi hash of entities needing a re-write - _entitiesNeedingRewrite.remove(baker->getFBXUrl()); + _entitiesNeedingRewrite.remove(baker->getModelURL()); // drop our shared pointer to this baker so that it gets cleaned up - _modelBakers.remove(baker->getFBXUrl()); + _modelBakers.remove(baker->getModelURL()); // emit progress to tell listeners how many models we have baked emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes); diff --git a/tools/oven/src/ui/BakeWidget.cpp b/tools/oven/src/ui/BakeWidget.cpp index 9fb8f2f880..fba9a46d9d 100644 --- a/tools/oven/src/ui/BakeWidget.cpp +++ b/tools/oven/src/ui/BakeWidget.cpp @@ -42,5 +42,5 @@ void BakeWidget::cancelButtonClicked() { auto stackedWidget = qobject_cast(parentWidget()); stackedWidget->removeWidget(this); - this->deleteLater(); + deleteLater(); } diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 0bef9f9414..c4c6dc1297 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -204,31 +204,30 @@ void ModelBakeWidget::bakeButtonClicked() { bakedOutputDirectory.mkdir("."); originalOutputDirectory.mkdir("."); + std::unique_ptr baker; + auto getWorkerThreadCallback = []() -> QThread* { + return qApp->getNextWorkerThread(); + }; // everything seems to be in place, kick off a bake for this model now if (modelToBakeURL.fileName().endsWith(".fbx")) { - _baker = std::unique_ptr{ - new FBXBaker(modelToBakeURL, []() -> QThread* { - return qApp->getNextWorkerThread(); - }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) - }; - _isFBX = true; + baker.reset(new FBXBaker(modelToBakeURL, getWorkerThreadCallback, bakedOutputDirectory.absolutePath(), + originalOutputDirectory.absolutePath())); } else if (modelToBakeURL.fileName().endsWith(".obj")) { - _baker = std::unique_ptr{ - new OBJBaker(modelToBakeURL, []() -> QThread* { - return qApp->getNextWorkerThread(); - }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) - }; - _isOBJ = true; + baker.reset(new OBJBaker(modelToBakeURL, getWorkerThreadCallback, bakedOutputDirectory.absolutePath(), + originalOutputDirectory.absolutePath())); + } else { + qWarning() << "Unknown model type: " << modelToBakeURL.fileName()); + continue; } // move the baker to the FBX/OBJ baker thread - _baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(qApp->getNextWorkerThread()); // invoke the bake method on the baker thread - QMetaObject::invokeMethod(_baker.get(), "bake"); + QMetaObject::invokeMethod(baker.get(), "bake"); // make sure we hear about the results of this baker when it is done - connect(_baker.get(), &Baker::finished, this, &ModelBakeWidget::handleFinishedBaker); + connect(baker.get(), &Baker::finished, this, &ModelBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); @@ -236,16 +235,15 @@ void ModelBakeWidget::bakeButtonClicked() { // keep a unique_ptr to this baker // and remember the row that represents it in the results table - _bakers.emplace_back(std::move(_baker), resultsRow); + _bakers.emplace_back(std::move(baker), resultsRow); } } void ModelBakeWidget::handleFinishedBaker() { - Baker* baker; - if (_isFBX) { - baker = qobject_cast(sender()); - } else if (_isOBJ) { - baker = qobject_cast(sender()); + Baker* baker = dynamic_cast(sender()); + if (!baker) { + qWarning() << "Received signal from unexpected sender"; + return; } // add the results of this bake to the results window diff --git a/tools/oven/src/ui/ModelBakeWidget.h b/tools/oven/src/ui/ModelBakeWidget.h index 02e7dde660..73527fbcc9 100644 --- a/tools/oven/src/ui/ModelBakeWidget.h +++ b/tools/oven/src/ui/ModelBakeWidget.h @@ -49,9 +49,6 @@ private: Setting::Handle _modelStartDirectory; std::unique_ptr _baker; - - bool _isOBJ = false; - bool _isFBX = false; }; #endif // hifi_ModelBakeWidget_h diff --git a/tools/oven/src/ui/OvenMainWindow.cpp b/tools/oven/src/ui/OvenMainWindow.cpp index dd40fb1f8f..bebc2fa7dc 100644 --- a/tools/oven/src/ui/OvenMainWindow.cpp +++ b/tools/oven/src/ui/OvenMainWindow.cpp @@ -46,7 +46,7 @@ ResultsWindow* OvenMainWindow::showResultsWindow(bool shouldRaise) { _resultsWindow->show(); // place the results window initially below our window - _resultsWindow->move(_resultsWindow->x(), this->frameGeometry().bottom()); + _resultsWindow->move(_resultsWindow->x(), frameGeometry().bottom()); } // show the results window and make sure it is in front diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index 0b12cb64ed..a52e948f01 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -41,18 +41,17 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) { } try { QByteArray fbxContents = fbx.readAll(); - FBXGeometry* geom; + FBXGeometry::Pointer geom; if (filename.toLower().endsWith(".obj")) { bool combineParts = false; geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts); } else if (filename.toLower().endsWith(".fbx")) { - geom = readFBX(fbxContents, QVariantHash(), filename); + geom.reset(readFBX(fbxContents, QVariantHash(), filename)); } else { qWarning() << "file has unknown extension" << filename; return false; } result = *geom; - delete geom; reSortFBXGeometryMeshes(result); } catch (const QString& error) { From 684300195054705512e891880421790346d5c051 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Dec 2017 14:03:33 -0800 Subject: [PATCH 26/33] Update TextureID/MaterialID in OBJBaker to be compatible with QVariant --- libraries/baking/src/OBJBaker.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 2e0d76e954..033057180f 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -20,8 +20,8 @@ using TextureBakerThreadGetter = std::function; -using TextureID = int64_t; -using MaterialID = int64_t; +using TextureID = qlonglong; +using MaterialID = qlonglong; class OBJBaker : public ModelBaker { Q_OBJECT From 53ce137b7c483440126e43436d245deffc7b5fc6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Dec 2017 15:56:35 -0800 Subject: [PATCH 27/33] Replace Texture/MaterialID in OBJBaker with NodeID --- libraries/baking/src/OBJBaker.cpp | 14 +++++++------- libraries/baking/src/OBJBaker.h | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index c4ca3485de..7159d9ed99 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -200,9 +200,9 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { FBXNode geometryNode; geometryNode.name = GEOMETRY_NODE_NAME; { - _geometryID = _nodeID; + _geometryID = nextNodeID(); geometryNode.properties = { - _nodeID++, + _geometryID, GEOMETRY_NODE_NAME, MESH }; @@ -218,8 +218,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { FBXNode modelNode; modelNode.name = MODEL_NODE_NAME; { - _modelID = _nodeID++; - modelNode.properties = { _nodeID, MODEL_NODE_NAME, MESH }; + _modelID = nextNodeID(); + modelNode.properties = { _modelID, MODEL_NODE_NAME, MESH }; } _objectNode.children = { geometryNode, modelNode }; @@ -248,13 +248,13 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { QString material = meshParts[i].materialID; FBXMaterial currentMaterial = geometry.materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { - _textureID = _nodeID; + _textureID = nextNodeID(); _mapTextureMaterial.emplace_back(_textureID, i); FBXNode textureNode; { textureNode.name = TEXTURE_NODE_NAME; - textureNode.properties = { _nodeID++ }; + textureNode.properties = { _textureID }; } // Texture node child - TextureName node @@ -336,7 +336,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Set properties for material nodes void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) { - auto materialID = _nodeID++; + auto materialID = nextNodeID(); _materialIDs.push_back(materialID); materialNode.properties = { materialID, material, MESH }; diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 033057180f..e888c7b1d8 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -20,8 +20,7 @@ using TextureBakerThreadGetter = std::function; -using TextureID = qlonglong; -using MaterialID = qlonglong; +using NodeID = qlonglong; class OBJBaker : public ModelBaker { Q_OBJECT @@ -42,13 +41,14 @@ private: void loadOBJ(); void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry); void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry); + NodeID nextNodeID() { return _nodeID++; } - qlonglong _nodeID = 0; - qlonglong _geometryID; - qlonglong _modelID; - std::vector _materialIDs; - qlonglong _textureID; - std::vector> _mapTextureMaterial; + NodeID _nodeID { 0 }; + NodeID _geometryID; + NodeID _modelID; + std::vector _materialIDs; + NodeID _textureID; + std::vector> _mapTextureMaterial; FBXNode _objectNode; }; #endif // hifi_OBJBaker_h From 7b48f0856608f5149f2a5844def591ca9a324ff1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Dec 2017 16:45:27 -0800 Subject: [PATCH 28/33] Remove _baker inside ModelBakeWidget --- tools/oven/src/ui/ModelBakeWidget.cpp | 2 ++ tools/oven/src/ui/ModelBakeWidget.h | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index c4c6dc1297..9248e2849c 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -23,9 +23,11 @@ #include "../Oven.h" #include "OvenMainWindow.h" +#include "FBXBaker.h" #include "OBJBaker.h" #include "ModelBakeWidget.h" + static const auto EXPORT_DIR_SETTING_KEY = "model_export_directory"; static const auto MODEL_START_DIR_SETTING_KEY = "model_search_directory"; diff --git a/tools/oven/src/ui/ModelBakeWidget.h b/tools/oven/src/ui/ModelBakeWidget.h index 73527fbcc9..fad623bf24 100644 --- a/tools/oven/src/ui/ModelBakeWidget.h +++ b/tools/oven/src/ui/ModelBakeWidget.h @@ -16,9 +16,6 @@ #include -#include -#include - #include "BakeWidget.h" class QLineEdit; @@ -47,8 +44,6 @@ private: Setting::Handle _exportDirectory; Setting::Handle _modelStartDirectory; - - std::unique_ptr _baker; }; #endif // hifi_ModelBakeWidget_h From 842d5cdb3903d44190ecdbf9248f3b026c69f50c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 5 Mar 2018 12:03:15 -0800 Subject: [PATCH 29/33] Fix erroneous syntax (unmatched paren) --- tools/oven/src/ui/ModelBakeWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 9248e2849c..5425c0069f 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -218,7 +218,7 @@ void ModelBakeWidget::bakeButtonClicked() { baker.reset(new OBJBaker(modelToBakeURL, getWorkerThreadCallback, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath())); } else { - qWarning() << "Unknown model type: " << modelToBakeURL.fileName()); + qWarning() << "Unknown model type: " << modelToBakeURL.fileName(); continue; } From 975f0bfbd2ce7ba22650b117b58895c623aaf624 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 7 Mar 2018 16:30:23 -0800 Subject: [PATCH 30/33] Fix OBJBaker not correctly waiting until all assets have been baked to finish --- libraries/baking/src/FBXBaker.cpp | 2 +- libraries/baking/src/ModelBaker.cpp | 1 + libraries/baking/src/OBJBaker.cpp | 14 ++++++++++++-- tools/oven/src/ui/ModelBakeWidget.cpp | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index e4405d91e3..0407c8508c 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -95,7 +95,7 @@ void FBXBaker::setupOutputFolder() { } // attempt to make the output folder if (!QDir().mkpath(_originalOutputDir)) { - handleError("Failed to create FBX output folder " + _bakedOutputDir); + handleError("Failed to create FBX output folder " + _originalOutputDir); return; } } diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index a6f366562b..1fec049259 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -327,6 +327,7 @@ void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type t void ModelBaker::handleBakedTexture() { TextureBaker* bakedTexture = qobject_cast(sender()); + qDebug() << "Handling baked texture" << bakedTexture->getTextureURL(); // make sure we haven't already run into errors, and that this is a valid texture if (bakedTexture) { diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 7159d9ed99..e806fe29db 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -150,6 +150,16 @@ void OBJBaker::bakeOBJ() { _bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename; + if (!QDir().mkpath(_bakedOutputDir)) { + handleError("Failed to create baked OBJ output folder " + _bakedOutputDir); + return; + } + + if (!QDir().mkpath(_originalOutputDir)) { + handleError("Failed to create original OBJ output folder " + _originalOutputDir); + return; + } + QFile bakedFile; bakedFile.setFileName(_bakedModelFilePath); if (!bakedFile.open(QIODevice::WriteOnly)) { @@ -163,8 +173,7 @@ void OBJBaker::bakeOBJ() { _outputFiles.push_back(_bakedModelFilePath); qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedModelFilePath; - // Export done emit finished - emit finished(); + checkIfTexturesFinished(); } void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { @@ -279,6 +288,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { auto textureFile = compressTexture(textureFileName, textureType); if (textureFile.isNull()) { // Baking failed return + handleError("Failed to compress texture: " + textureFileName); return; } relativeFilenameNode.properties = { textureFile }; diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 5425c0069f..b660a145b7 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -191,7 +191,7 @@ void ModelBakeWidget::bakeButtonClicked() { subFolderName = modelName + "-" + QString::number(++iteration) + "/"; } - outputDirectory.mkdir(subFolderName); + outputDirectory.mkpath(subFolderName); if (!outputDirectory.exists()) { QMessageBox::warning(this, "Unable to create directory", "Unable to create output directory. Please create it manually or choose a different directory."); From 004e15d2d9fe03ab8c3c698df66a9a6c8c023c33 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 7 Mar 2018 16:31:41 -0800 Subject: [PATCH 31/33] Update ATP to be optional in ResourceManager for OBJBaker --- libraries/networking/src/ResourceManager.cpp | 16 +++++++++++----- libraries/networking/src/ResourceManager.h | 3 ++- tools/oven/src/Oven.cpp | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 317cabdc61..d06b74b724 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -26,12 +26,14 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" -ResourceManager::ResourceManager() { +ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) { _thread.setObjectName("Resource Manager Thread"); - auto assetClient = DependencyManager::set(); - assetClient->moveToThread(&_thread); - QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::initCaching); + if (_atpSupportEnabled) { + auto assetClient = DependencyManager::set(); + assetClient->moveToThread(&_thread); + QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::initCaching); + } _thread.start(); } @@ -111,6 +113,10 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { request = new HTTPResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_ATP) { + if (!_atpSupportEnabled) { + qCDebug(networking) << "ATP support not enabled, unable to create request for URL: " << url.url(); + return nullptr; + } request = new AssetResourceRequest(normalizedURL); } else { qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url(); @@ -146,7 +152,7 @@ bool ResourceManager::resourceExists(const QUrl& url) { reply->deleteLater(); return reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200; - } else if (scheme == URL_SCHEME_ATP) { + } else if (scheme == URL_SCHEME_ATP && _atpSupportEnabled) { auto request = new AssetResourceRequest(url); ByteRange range; range.fromInclusive = 1; diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index 5728a7bd32..d5fa2aa0e2 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -34,7 +34,7 @@ class ResourceManager: public QObject, public Dependency { SINGLETON_DEPENDENCY public: - ResourceManager(); + ResourceManager(bool atpSupportEnabled = true); void setUrlPrefixOverride(const QString& prefix, const QString& replacement); QString normalizeURL(const QString& urlString); @@ -57,6 +57,7 @@ private: using PrefixMap = std::map; + bool _atpSupportEnabled; PrefixMap _prefixMap; QMutex _prefixMapLock; diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index 0686646b93..a689ca0c84 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -54,6 +54,10 @@ Oven::Oven(int argc, char* argv[]) : // setup our worker threads setupWorkerThreads(QThread::idealThreadCount()); + // Initialize dependencies for OBJ Baker + DependencyManager::set(); + DependencyManager::set(false); + // check if we were passed any command line arguments that would tell us just to run without the GUI if (parser.isSet(CLI_INPUT_PARAMETER) || parser.isSet(CLI_OUTPUT_PARAMETER)) { if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { From a5e491e29de82ddada5fb806cbdf622def1b66f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Mar 2018 10:38:21 -0700 Subject: [PATCH 32/33] Add OBJ support to domain baker --- libraries/baking/src/ModelBaker.cpp | 2 ++ libraries/baking/src/ModelBaker.h | 1 + libraries/baking/src/OBJBaker.cpp | 20 ++++++------- tools/oven/src/DomainBaker.cpp | 45 +++++++++++++++++++---------- tools/oven/src/DomainBaker.h | 2 +- 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 1fec049259..16a0c89c7f 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -405,6 +405,8 @@ void ModelBaker::handleAbortedTexture() { // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore TextureBaker* bakedTexture = qobject_cast(sender()); + qDebug() << "Texture aborted: " << bakedTexture->getTextureURL(); + if (bakedTexture) { _bakingTextures.remove(bakedTexture->getTextureURL()); } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 944b9b8f2a..6fd529af92 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -36,6 +36,7 @@ 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 = nullptr); QString compressTexture(QString textureFileName, image::TextureUsage::Type = image::TextureUsage::Type::DEFAULT_TEXTURE); virtual void setWasAborted(bool wasAborted) override; diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index e806fe29db..85771ff2e3 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -45,6 +45,16 @@ void OBJBaker::bake() { } void OBJBaker::loadOBJ() { + if (!QDir().mkpath(_bakedOutputDir)) { + handleError("Failed to create baked OBJ output folder " + _bakedOutputDir); + return; + } + + if (!QDir().mkpath(_originalOutputDir)) { + handleError("Failed to create original OBJ output folder " + _originalOutputDir); + return; + } + // check if the OBJ is local or it needs to be downloaded if (_modelURL.isLocalFile()) { // loading the local OBJ @@ -150,16 +160,6 @@ void OBJBaker::bakeOBJ() { _bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename; - if (!QDir().mkpath(_bakedOutputDir)) { - handleError("Failed to create baked OBJ output folder " + _bakedOutputDir); - return; - } - - if (!QDir().mkpath(_originalOutputDir)) { - handleError("Failed to create original OBJ output folder " + _originalOutputDir); - return; - } - QFile bakedFile; bakedFile.setFileName(_bakedModelFilePath); if (!bakedFile.open(QIODevice::WriteOnly)) { diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index f1eb9d11e4..45621f5127 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainBaker.h" + #include #include #include @@ -17,10 +19,9 @@ #include #include "Gzip.h" - #include "Oven.h" - -#include "DomainBaker.h" +#include "FBXBaker.h" +#include "OBJBaker.h" DomainBaker::DomainBaker(const QUrl& localModelFileURL, const QString& domainName, const QString& baseOutputPath, const QUrl& destinationPath, @@ -167,15 +168,18 @@ void DomainBaker::enumerateEntities() { // check if the file pointed to by this URL is a bakeable model, by comparing extensions auto modelFileName = modelURL.fileName(); - static const QString BAKEABLE_MODEL_EXTENSION { ".fbx" }; + static const QString BAKEABLE_MODEL_FBX_EXTENSION { ".fbx" }; + static const QString BAKEABLE_MODEL_OBJ_EXTENSION { ".obj" }; static const QString BAKED_MODEL_EXTENSION = ".baked.fbx"; - bool isBakedFBX = modelFileName.endsWith(BAKED_MODEL_EXTENSION, Qt::CaseInsensitive); - bool isUnbakedFBX = modelFileName.endsWith(BAKEABLE_MODEL_EXTENSION, Qt::CaseInsensitive) && !isBakedFBX; + bool isBakedModel = modelFileName.endsWith(BAKED_MODEL_EXTENSION, Qt::CaseInsensitive); + bool isBakeableFBX = modelFileName.endsWith(BAKEABLE_MODEL_FBX_EXTENSION, Qt::CaseInsensitive); + bool isBakeableOBJ = modelFileName.endsWith(BAKEABLE_MODEL_OBJ_EXTENSION, Qt::CaseInsensitive); + bool isBakeable = isBakeableFBX || isBakeableOBJ; - if (isUnbakedFBX || (_shouldRebakeOriginals && isBakedFBX)) { + if (isBakeable || (_shouldRebakeOriginals && isBakedModel)) { - if (isBakedFBX) { + if (isBakedModel) { // grab a URL to the original, that we assume is stored a directory up, in the "original" folder // with just the fbx extension qDebug() << "Re-baking original for" << modelURL; @@ -190,7 +194,7 @@ void DomainBaker::enumerateEntities() { modelURL = modelURL.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment); } - // setup an FBXBaker for this URL, as long as we don't already have one + // setup a ModelBaker for this URL, as long as we don't already have one if (!_modelBakers.contains(modelURL)) { auto filename = modelURL.fileName(); auto baseName = filename.left(filename.lastIndexOf('.')); @@ -199,12 +203,23 @@ void DomainBaker::enumerateEntities() { while (QDir(_contentOutputPath + subDirName).exists()) { subDirName = "/" + baseName + "-" + QString::number(i++); } - QSharedPointer baker { - new FBXBaker(modelURL, []() -> QThread* { - return qApp->getNextWorkerThread(); - }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), - &FBXBaker::deleteLater - }; + + QSharedPointer baker; + if (isBakeableFBX) { + baker = { + new FBXBaker(modelURL, []() -> QThread* { + return qApp->getNextWorkerThread(); + }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), + &FBXBaker::deleteLater + }; + } else { + baker = { + new OBJBaker(modelURL, []() -> QThread* { + return qApp->getNextWorkerThread(); + }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), + &FBXBaker::deleteLater + }; + } // make sure our handler is called when the baker is done connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedModelBaker); diff --git a/tools/oven/src/DomainBaker.h b/tools/oven/src/DomainBaker.h index 6426af0710..e0286a51ff 100644 --- a/tools/oven/src/DomainBaker.h +++ b/tools/oven/src/DomainBaker.h @@ -61,7 +61,7 @@ private: QJsonArray _entities; - QHash> _modelBakers; + QHash> _modelBakers; QHash> _skyboxBakers; QMultiHash _entitiesNeedingRewrite; From bcbe55d751a4cf60db6cb5dae1c6b4044bc6c3cf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Mar 2018 14:30:42 -0700 Subject: [PATCH 33/33] Fix OBJ support in DomainBaker --- tools/oven/src/DomainBaker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index 45621f5127..a2bf2940a7 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -217,7 +217,7 @@ void DomainBaker::enumerateEntities() { new OBJBaker(modelURL, []() -> QThread* { return qApp->getNextWorkerThread(); }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), - &FBXBaker::deleteLater + &OBJBaker::deleteLater }; } @@ -314,7 +314,7 @@ void DomainBaker::bakeSkybox(QUrl skyboxURL, QJsonValueRef entity) { } void DomainBaker::handleFinishedModelBaker() { - auto baker = qobject_cast(sender()); + auto baker = qobject_cast(sender()); if (baker) { if (!baker->hasErrors()) {