From 28baed18c0a56fd2b7f3085da12cdef0db7a5365 Mon Sep 17 00:00:00 2001 From: utkarshgautamnyu Date: Fri, 20 Oct 2017 18:55:41 -0700 Subject: [PATCH 01/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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 747a6b07ceeb55148edb8bdd807e01a1c19f982e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 11:19:49 -0800 Subject: [PATCH 32/45] Fix font loading for MacOS via different font loading method --- interface/resources/qml/CurrentAPI.qml | 2 -- .../resources/qml/controls-uit/CheckBoxQQC2.qml | 4 ++-- interface/resources/qml/controls-uit/Keyboard.qml | 9 +++------ interface/resources/qml/controls-uit/SpinBox.qml | 3 +-- interface/resources/qml/controls-uit/TextEdit.qml | 6 +++--- interface/resources/qml/controls-uit/TextField.qml | 4 +--- interface/resources/qml/controls/FontAwesome.qml | 3 +-- interface/resources/qml/dialogs/FileDialog.qml | 5 +---- interface/resources/qml/dialogs/TabletFileDialog.qml | 5 +---- .../qml/dialogs/assetDialog/AssetDialogContent.qml | 5 +---- interface/resources/qml/hifi/AssetServer.qml | 10 ++++++---- interface/resources/qml/hifi/ComboDialog.qml | 2 -- .../resources/qml/hifi/DesktopLetterboxMessage.qml | 7 +++---- interface/resources/qml/hifi/LetterboxMessage.qml | 7 +++---- interface/resources/qml/hifi/NameCard.qml | 3 +-- interface/resources/qml/hifi/Pal.qml | 3 +-- .../commerce/common/EmulatedMarketplaceHeader.qml | 3 +-- .../qml/hifi/commerce/wallet/sendMoney/SendMoney.qml | 5 ++--- .../resources/qml/hifi/dialogs/TabletAssetServer.qml | 12 +++++++----- .../hifi/tablet/tabletWindows/TabletFileDialog.qml | 5 +---- .../resources/qml/styles-uit/AnonymousProRegular.qml | 3 +-- .../resources/qml/styles-uit/FiraSansRegular.qml | 3 +-- .../resources/qml/styles-uit/FiraSansSemiBold.qml | 3 +-- interface/resources/qml/styles-uit/HiFiGlyphs.qml | 3 +-- interface/resources/qml/styles-uit/RalewayBold.qml | 5 ++--- interface/resources/qml/styles-uit/RalewayLight.qml | 3 +-- .../resources/qml/styles-uit/RalewayRegular.qml | 3 +-- .../resources/qml/styles-uit/RalewaySemiBold.qml | 4 ++-- interface/src/Application.cpp | 9 +++++++++ 29 files changed, 58 insertions(+), 81 deletions(-) diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 37984965d9..96bfb5c36b 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -33,8 +33,6 @@ Item { width: parent.width height: parent.height } - - FontLoader { id: ralewayRegular; source: pathToFonts + "fonts/Raleway-Regular.ttf"; } Timer { id: updateList diff --git a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml index 12b8c80003..8a9686ff5e 100644 --- a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml @@ -109,9 +109,9 @@ CheckBox { contentItem: Text { id: root - FontLoader { id: ralewaySemiBold; source: pathToFonts + "fonts/Raleway-SemiBold.ttf"; } font.pixelSize: hifi.fontSizes.inputLabel - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold text: checkBox.text color: checkBox.color x: 2 diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 76b66178d4..ea76d44aaa 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -125,8 +125,7 @@ Rectangle { TextInput { id: mirrorText visible: showMirrorText - FontLoader { id: font; source: "../../fonts/FiraSans-Regular.ttf"; } - font.family: font.name + font.family: "Fira Sans" font.pixelSize: 20 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter @@ -165,8 +164,6 @@ Rectangle { anchors.bottom: parent.bottom anchors.bottomMargin: 0 - FontLoader { id: hiFiGlyphs; source: pathToFonts + "fonts/hifi-glyphs.ttf"; } - Column { id: columnAlpha width: keyboardWidth @@ -250,7 +247,7 @@ Rectangle { Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } Key { - fontFamily: hiFiGlyphs.name; + fontFamily: "hifi-glyphs"; fontPixelSize: 48; letterAnchors.topMargin: -4; verticalAlignment: Text.AlignVCenter; @@ -343,7 +340,7 @@ Rectangle { Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } Key { - fontFamily: hiFiGlyphs.name; + fontFamily: "hifi-glyphs"; fontPixelSize: 48; letterAnchors.topMargin: -4; verticalAlignment: Text.AlignVCenter; diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index a1237d4bc7..30f6682d5a 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -25,8 +25,7 @@ SpinBox { property color colorLabelInside: hifi.colors.white property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0) - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control. diff --git a/interface/resources/qml/controls-uit/TextEdit.qml b/interface/resources/qml/controls-uit/TextEdit.qml index 5ee9ce94ba..0fe03150f4 100644 --- a/interface/resources/qml/controls-uit/TextEdit.qml +++ b/interface/resources/qml/controls-uit/TextEdit.qml @@ -16,9 +16,9 @@ import "../styles-uit" TextEdit { property real size: 32 - - FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } - font.family: ralewaySemiBold.name + + font.family: "Raleway" + font.weight: Font.DemiBold font.pointSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index 3fc5d83129..782ab454b5 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -34,9 +34,7 @@ TextField { placeholderText: textField.placeholderText - FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; } - FontLoader { id: hifiGlyphs; source: "../../fonts/hifi-glyphs.ttf"; } - font.family: firaSansRegular.name + font.family: "Fira Sans" font.pixelSize: hifi.fontSizes.textFieldInput height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered. property alias textFieldLabel: textFieldLabel diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml index 50d7e96fb5..2c897b6347 100644 --- a/interface/resources/qml/controls/FontAwesome.qml +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -4,13 +4,12 @@ import QtQuick.Controls.Styles 1.3 Text { id: root - FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } property int size: 32 width: size height: size font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: iconFont.name + font.family: "FontAwesome" } diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 0b5da8a5f5..572e7a7918 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -532,9 +532,6 @@ ModalWindow { itemDelegate: Item { clip: true - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -548,7 +545,7 @@ ModalWindow { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - ? firaSansSemiBold.name : firaSansRegular.name + ? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index d3b738469e..c635095ac6 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -496,9 +496,6 @@ TabletModalWindow { itemDelegate: Item { clip: true - //FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - //FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -512,7 +509,7 @@ TabletModalWindow { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight //font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - //? firaSansSemiBold.name : firaSansRegular.name + //? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index 8c0501e3b4..84f4c694ff 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -345,9 +345,6 @@ Item { itemDelegate: Item { clip: true - FontLoader { id: firaSansSemiBold; source: "../../../fonts/FiraSans-SemiBold.ttf"; } - FontLoader { id: firaSansRegular; source: "../../../fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: styleData.value elide: styleData.elideMode @@ -361,7 +358,7 @@ Item { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir) - ? firaSansSemiBold.name : firaSansRegular.name + ? "Fira Sans SemiBold" : "Fira Sans" } } diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index fea275999e..34be11d4df 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -187,9 +187,10 @@ Windows.ScrollingWindow { var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; + var collisionless = true; var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, position, gravity); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; @@ -234,6 +235,7 @@ Windows.ScrollingWindow { var result = JSON.parse(jsonResult); var url = result.textInput.trim(); var shapeType; + var collisionless = false; switch (result.comboBox) { case SHAPE_TYPE_SIMPLE_HULL: shapeType = "simple-hull"; @@ -252,6 +254,7 @@ Windows.ScrollingWindow { break; default: shapeType = "none"; + collisionless = true; } var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; @@ -273,7 +276,7 @@ Windows.ScrollingWindow { print("Asset browser - adding asset " + url + " (" + name + ") to world."); // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); + Entities.addModelEntity(name, url, "", shapeType, dynamic, collisionless, addPosition, gravity); } } }); @@ -657,8 +660,7 @@ Windows.ScrollingWindow { text: styleData.value - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index 83fcad18c7..06254bb7fb 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -25,8 +25,6 @@ Item { property int dialogHeight; property int comboOptionTextSize: 16; property int comboBodyTextSize: 16; - FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } visible: false; id: combo; anchors.fill: parent; diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml index bafa518eb9..ede8590bfb 100644 --- a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -24,8 +24,6 @@ Item { property real headerTextMargin: -5 property real headerGlyphMargin: -15 property bool isDesktop: false - FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } visible: false id: letterbox anchors.fill: parent @@ -78,7 +76,8 @@ Item { // Text Size font.pixelSize: headerTextPixelSize // Style - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold color: hifi.colors.darkGray horizontalAlignment: Text.AlignHLeft verticalAlignment: Text.AlignVCenter @@ -101,7 +100,7 @@ Item { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: popupTextPixelSize - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 7ce66adf11..0e9ce89ddb 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -23,8 +23,6 @@ Item { property real popupTextPixelSize: 16 property real headerTextMargin: -5 property real headerGlyphMargin: -15 - FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } visible: false id: letterbox anchors.fill: parent @@ -82,7 +80,8 @@ Item { // Text Size font.pixelSize: headerTextPixelSize // Style - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold color: hifi.colors.darkGray horizontalAlignment: Text.AlignHLeft verticalAlignment: Text.AlignVCenter @@ -127,7 +126,7 @@ Item { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: popupTextPixelSize - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index e08fdc53ff..c97a802f10 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -177,8 +177,7 @@ Item { anchors.right: parent.right anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin // Style - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: displayNameTextPixelSize selectionColor: hifi.colors.blueAccent selectedTextColor: "black" diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 8fb27714ee..d779b4ba42 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -908,7 +908,6 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter; } - FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; } Text { id: connectionHelpText; // Anchors @@ -923,7 +922,7 @@ Rectangle { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: 18; - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText; diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index eb8159a4e7..8a7e809b3d 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -141,10 +141,9 @@ Item { } } - FontLoader { id: ralewayRegular; source: "../../../../fonts/Raleway-Regular.ttf"; } TextMetrics { id: textMetrics; - font.family: ralewayRegular.name + font.family: "Raleway" text: usernameText.text; } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index f5b7f42a3f..d0aa89923f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -924,14 +924,13 @@ Item { anchors.right: parent.right; anchors.rightMargin: 20; height: 95; - - FontLoader { id: firaSansSemiBold; source: "../../../../../fonts/FiraSans-SemiBold.ttf"; } + TextArea { id: optionalMessage; property int maximumLength: 72; property string previousText: text; placeholderText: "Optional Public Message (" + maximumLength + " character limit)"; - font.family: firaSansSemiBold.name; + font.family: "Fira Sans SemiBold"; font.pixelSize: 20; // Anchors anchors.fill: parent; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 19297a3251..a85e5d4498 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -144,7 +144,7 @@ Rectangle { } function canAddToWorld(path) { - var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; + var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; if (selectedItemCount > 1) { return false; @@ -188,9 +188,10 @@ Rectangle { var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; + var collisionless = true; var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, position, gravity); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; @@ -235,6 +236,7 @@ Rectangle { var result = JSON.parse(jsonResult); var url = result.textInput.trim(); var shapeType; + var collisionless = false; switch (result.comboBox) { case SHAPE_TYPE_SIMPLE_HULL: shapeType = "simple-hull"; @@ -253,6 +255,7 @@ Rectangle { break; default: shapeType = "none"; + collisionless = true; } var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; @@ -274,7 +277,7 @@ Rectangle { print("Asset browser - adding asset " + url + " (" + name + ") to world."); // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); + Entities.addModelEntity(name, url, "", shapeType, dynamic, collisionless, addPosition, gravity); } } }); @@ -656,8 +659,7 @@ Rectangle { text: styleData.value - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml index 7b91cfeba9..08b0104fce 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml @@ -478,9 +478,6 @@ Rectangle { itemDelegate: Item { clip: true - //FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - //FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -494,7 +491,7 @@ Rectangle { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight //font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - //? firaSansSemiBold.name : firaSansRegular.name + //? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/styles-uit/AnonymousProRegular.qml b/interface/resources/qml/styles-uit/AnonymousProRegular.qml index 789689973b..d7e13423b6 100644 --- a/interface/resources/qml/styles-uit/AnonymousProRegular.qml +++ b/interface/resources/qml/styles-uit/AnonymousProRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: anonymousProRegular; source: "../../fonts/AnonymousPro-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: anonymousProRegular.name + font.family: "Anonymous Pro" } diff --git a/interface/resources/qml/styles-uit/FiraSansRegular.qml b/interface/resources/qml/styles-uit/FiraSansRegular.qml index 4ae0826772..1166fa5cba 100644 --- a/interface/resources/qml/styles-uit/FiraSansRegular.qml +++ b/interface/resources/qml/styles-uit/FiraSansRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: firaSansRegular.name + font.family: "Fira Sans" } diff --git a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml index b3f3324090..2f095c57a6 100644 --- a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml +++ b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: firaSansSemiBold; source: pathToFonts + "fonts/FiraSans-SemiBold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" } diff --git a/interface/resources/qml/styles-uit/HiFiGlyphs.qml b/interface/resources/qml/styles-uit/HiFiGlyphs.qml index f78d6c6f59..07f0212f0c 100644 --- a/interface/resources/qml/styles-uit/HiFiGlyphs.qml +++ b/interface/resources/qml/styles-uit/HiFiGlyphs.qml @@ -12,12 +12,11 @@ import QtQuick 2.5 Text { id: root - FontLoader { id: hiFiGlyphs; source: pathToFonts + "fonts/hifi-glyphs.ttf"; } property int size: 32 font.pixelSize: size width: size height: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: hiFiGlyphs.name + font.family: "hifi-glyphs" } diff --git a/interface/resources/qml/styles-uit/RalewayBold.qml b/interface/resources/qml/styles-uit/RalewayBold.qml index 433fdb7ae6..5f42ecd90b 100644 --- a/interface/resources/qml/styles-uit/RalewayBold.qml +++ b/interface/resources/qml/styles-uit/RalewayBold.qml @@ -14,11 +14,10 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayBold; source: pathToFonts + "fonts/Raleway-Bold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayBold.name - font.bold: true // Font seems to need this in order to display bold. + font.family: "Raleway" + font.bold: true } diff --git a/interface/resources/qml/styles-uit/RalewayLight.qml b/interface/resources/qml/styles-uit/RalewayLight.qml index 913918afd7..e6b12fca9c 100644 --- a/interface/resources/qml/styles-uit/RalewayLight.qml +++ b/interface/resources/qml/styles-uit/RalewayLight.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayLight; source: "../../fonts/Raleway-Light.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayLight.name + font.family: "Raleway Light" } diff --git a/interface/resources/qml/styles-uit/RalewayRegular.qml b/interface/resources/qml/styles-uit/RalewayRegular.qml index aab31ecf33..5c9b87dc8a 100644 --- a/interface/resources/qml/styles-uit/RalewayRegular.qml +++ b/interface/resources/qml/styles-uit/RalewayRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayRegular; source: pathToFonts + "fonts/Raleway-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayRegular.name + font.family: "Raleway" } diff --git a/interface/resources/qml/styles-uit/RalewaySemiBold.qml b/interface/resources/qml/styles-uit/RalewaySemiBold.qml index b6c79e02a4..0b25f900bc 100644 --- a/interface/resources/qml/styles-uit/RalewaySemiBold.qml +++ b/interface/resources/qml/styles-uit/RalewaySemiBold.qml @@ -14,10 +14,10 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewaySemiBold; source: pathToFonts + "fonts/Raleway-SemiBold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 429348c593..15f772b02a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -978,6 +978,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); + QFontDatabase::addApplicationFont(":/fonts/fontawesome-webfont.ttf"); + QFontDatabase::addApplicationFont(":/fonts/hifi-glyphs.ttf"); + QFontDatabase::addApplicationFont(":/fonts/AnonymousPro-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/FiraSans-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/FiraSans-SemiBold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Light.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Bold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us From ec6f66ee521631525f00c31931be64c313d24898 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 13:51:34 -0800 Subject: [PATCH 33/45] Try this --- interface/src/Application.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 15f772b02a..a25c9e43cb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -978,15 +978,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); - QFontDatabase::addApplicationFont(":/fonts/fontawesome-webfont.ttf"); - QFontDatabase::addApplicationFont(":/fonts/hifi-glyphs.ttf"); - QFontDatabase::addApplicationFont(":/fonts/AnonymousPro-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/FiraSans-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/FiraSans-SemiBold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Light.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Bold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-SemiBold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/fontawesome-webfont.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/hifi-glyphs.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/AnonymousPro-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-SemiBold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Light.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Bold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us From 883528488cde5c3acc41c23a2c289065a70aa121 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 8 Mar 2018 14:24:44 -0800 Subject: [PATCH 34/45] clear wallet when picking a new one --- .../qml/hifi/commerce/wallet/Wallet.qml | 3 ++- interface/src/commerce/QmlCommerce.cpp | 5 ++++ interface/src/commerce/QmlCommerce.h | 1 + interface/src/commerce/Wallet.cpp | 24 +++++++++++-------- interface/src/commerce/Wallet.h | 3 ++- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 952390a7a4..1d5f749598 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -174,11 +174,12 @@ Rectangle { WalletChoice { id: walletChoice; proceedFunction: function (isReset) { - console.log(isReset ? "Reset wallet." : "Trying again with new wallet."); + console.log("WalletChoice", isReset ? "Reset wallet." : "Trying again with new wallet."); Commerce.setSoftReset(); if (isReset) { walletResetSetup(); } else { + Commerce.clearWallet(); var msg = { referrer: walletChoice.referrer } followReferrer(msg); } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 557193c074..53ec59049f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -138,6 +138,11 @@ void QmlCommerce::setSoftReset() { wallet->setSoftReset(); } +void QmlCommerce::clearWallet() { + auto wallet = DependencyManager::get(); + wallet->clear(); +} + void QmlCommerce::setPassphrase(const QString& passphrase) { auto wallet = DependencyManager::get(); wallet->setPassphrase(passphrase); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 6a4eaa2be2..b4af4393e3 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -67,6 +67,7 @@ protected: Q_INVOKABLE void setPassphrase(const QString& passphrase); Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase); Q_INVOKABLE void setSoftReset(); + Q_INVOKABLE void clearWallet(); Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); Q_INVOKABLE void balance(); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index fad82115d6..060f8de09b 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -343,19 +343,23 @@ Wallet::Wallet() { auto accountManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { getWalletStatus(); - _publicKeys.clear(); - - if (_securityImage) { - delete _securityImage; - } - _securityImage = nullptr; - - // tell the provider we got nothing - updateImageProvider(); - _passphrase->clear(); + clear(); }); } +void Wallet::clear() { + _publicKeys.clear(); + + if (_securityImage) { + delete _securityImage; + } + _securityImage = nullptr; + + // tell the provider we got nothing + updateImageProvider(); + _passphrase->clear(); +} + Wallet::~Wallet() { if (_securityImage) { delete _securityImage; diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index d771f404e5..8a7d6b8c07 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -49,8 +49,9 @@ public: bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); } bool walletIsAuthenticatedWithPassphrase(); bool changePassphrase(const QString& newPassphrase); - void setSoftReset() { _isOverridingServer = true; } + void setSoftReset() { _isOverridingServer = true; } bool wasSoftReset() { bool was = _isOverridingServer; _isOverridingServer = false; return was; } + void clear(); void getWalletStatus(); enum WalletStatus { From c22d79041db348344ec3b16c3e9703410394ea29 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 14:35:56 -0800 Subject: [PATCH 35/45] Cleanup after cherry-pick --- interface/resources/qml/hifi/AssetServer.qml | 7 ++----- .../resources/qml/hifi/dialogs/TabletAssetServer.qml | 9 +++------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 34be11d4df..7a9e0707c1 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -187,10 +187,9 @@ Windows.ScrollingWindow { var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; - var collisionless = true; var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, position, gravity); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; @@ -235,7 +234,6 @@ Windows.ScrollingWindow { var result = JSON.parse(jsonResult); var url = result.textInput.trim(); var shapeType; - var collisionless = false; switch (result.comboBox) { case SHAPE_TYPE_SIMPLE_HULL: shapeType = "simple-hull"; @@ -254,7 +252,6 @@ Windows.ScrollingWindow { break; default: shapeType = "none"; - collisionless = true; } var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; @@ -276,7 +273,7 @@ Windows.ScrollingWindow { print("Asset browser - adding asset " + url + " (" + name + ") to world."); // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, "", shapeType, dynamic, collisionless, addPosition, gravity); + Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); } } }); diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a85e5d4498..a61241ff7c 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -144,7 +144,7 @@ Rectangle { } function canAddToWorld(path) { - var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; + var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; if (selectedItemCount > 1) { return false; @@ -188,10 +188,9 @@ Rectangle { var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; - var collisionless = true; var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, position, gravity); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; @@ -236,7 +235,6 @@ Rectangle { var result = JSON.parse(jsonResult); var url = result.textInput.trim(); var shapeType; - var collisionless = false; switch (result.comboBox) { case SHAPE_TYPE_SIMPLE_HULL: shapeType = "simple-hull"; @@ -255,7 +253,6 @@ Rectangle { break; default: shapeType = "none"; - collisionless = true; } var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; @@ -277,7 +274,7 @@ Rectangle { print("Asset browser - adding asset " + url + " (" + name + ") to world."); // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, "", shapeType, dynamic, collisionless, addPosition, gravity); + Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); } } }); From b427d6c326222ac8e7057b68c994ac368d79a20a Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 8 Mar 2018 23:07:12 +0300 Subject: [PATCH 36/45] FB12956 - Audio Meter Toggle Button Broken --- .../qml/{AvatarInputs.qml => AvatarInputsBar.qml} | 6 +++--- interface/src/Application.cpp | 7 ++++++- interface/src/ui/AvatarInputs.cpp | 7 ++----- interface/src/ui/AvatarInputs.h | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) rename interface/resources/qml/{AvatarInputs.qml => AvatarInputsBar.qml} (88%) diff --git a/interface/resources/qml/AvatarInputs.qml b/interface/resources/qml/AvatarInputsBar.qml similarity index 88% rename from interface/resources/qml/AvatarInputs.qml rename to interface/resources/qml/AvatarInputsBar.qml index be4bf03465..a88a42080e 100644 --- a/interface/resources/qml/AvatarInputs.qml +++ b/interface/resources/qml/AvatarInputsBar.qml @@ -14,9 +14,9 @@ import Qt.labs.settings 1.0 import "./hifi/audio" as HifiAudio -Hifi.AvatarInputs { +Item { id: root; - objectName: "AvatarInputs" + objectName: "AvatarInputsBar" property int modality: Qt.NonModal width: audio.width; height: audio.height; @@ -26,7 +26,7 @@ Hifi.AvatarInputs { HifiAudio.MicBar { id: audio; - visible: root.showAudioTools; + visible: AvatarInputs.showAudioTools; standalone: true; dragTarget: parent; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 429348c593..8fd43c95a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2716,7 +2716,12 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { Stats::show(); - AvatarInputs::show(); + auto surfaceContext = DependencyManager::get()->getSurfaceContext(); + surfaceContext->setContextProperty("Stats", Stats::getInstance()); + + auto offscreenUi = DependencyManager::get(); + auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml"); + offscreenUi->show(qml, "AvatarInputsBar"); } void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index fe79bec6ef..3053cb8855 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -16,22 +16,19 @@ #include "Application.h" #include "Menu.h" -HIFI_QML_DEF(AvatarInputs) - static AvatarInputs* INSTANCE{ nullptr }; Setting::Handle showAudioToolsSetting { QStringList { "AvatarInputs", "showAudioTools" }, false }; AvatarInputs* AvatarInputs::getInstance() { if (!INSTANCE) { - AvatarInputs::registerType(); + INSTANCE = new AvatarInputs(); Q_ASSERT(INSTANCE); } return INSTANCE; } -AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { - INSTANCE = this; +AvatarInputs::AvatarInputs(QObject* parent) : QObject(parent) { _showAudioTools = showAudioToolsSetting.get(); } diff --git a/interface/src/ui/AvatarInputs.h b/interface/src/ui/AvatarInputs.h index fb48df9d73..47f520a639 100644 --- a/interface/src/ui/AvatarInputs.h +++ b/interface/src/ui/AvatarInputs.h @@ -19,7 +19,7 @@ public: \ private: \ type _##name{ initialValue }; -class AvatarInputs : public QQuickItem { +class AvatarInputs : public QObject { Q_OBJECT HIFI_QML_DECL @@ -32,7 +32,7 @@ class AvatarInputs : public QQuickItem { public: static AvatarInputs* getInstance(); Q_INVOKABLE float loudnessToAudioLevel(float loudness); - AvatarInputs(QQuickItem* parent = nullptr); + AvatarInputs(QObject* parent = nullptr); void update(); bool showAudioTools() const { return _showAudioTools; } From a5e491e29de82ddada5fb806cbdf622def1b66f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Mar 2018 10:38:21 -0700 Subject: [PATCH 37/45] 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 38/45] 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()) { From 271badfa626e8620192a9058668b385b689d0ebc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 13 Mar 2018 16:33:32 -0700 Subject: [PATCH 39/45] provide an overlay property to control if the overlay is visible in the secondary camera view --- interface/src/ui/overlays/Base3DOverlay.cpp | 15 ++++++++++++++- interface/src/ui/overlays/Base3DOverlay.h | 3 +++ interface/src/ui/overlays/ModelOverlay.cpp | 4 +++- interface/src/ui/overlays/Overlay.h | 2 ++ interface/src/ui/overlays/OverlaysPayload.cpp | 6 +++++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index ff5a202910..f4efd1301d 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -37,7 +37,8 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : _ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection), _drawInFront(base3DOverlay->_drawInFront), _drawHUDLayer(base3DOverlay->_drawHUDLayer), - _isGrabbable(base3DOverlay->_isGrabbable) + _isGrabbable(base3DOverlay->_isGrabbable), + _isVisibleInSecondaryCamera(base3DOverlay->_isVisibleInSecondaryCamera) { setTransform(base3DOverlay->getTransform()); } @@ -142,6 +143,13 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { setIsGrabbable(isGrabbable.toBool()); } + auto isVisibleInSecondaryCamera = properties["isVisibleInSecondaryCamera"]; + if (isVisibleInSecondaryCamera.isValid()) { + bool value = isVisibleInSecondaryCamera.toBool(); + setIsVisibleInSecondaryCamera(value); + needRenderItemUpdate = true; + } + if (properties["position"].isValid()) { setLocalPosition(vec3FromVariant(properties["position"])); needRenderItemUpdate = true; @@ -221,6 +229,8 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { * @property {boolean} drawInFront=false - If true, the overlay is rendered in front of other overlays that don't * have drawInFront set to true, and in front of entities. * @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed. + * @property {boolean} isVisibleInSecondaryCamera=false - If true, the overlay is rendered in secondary + * camera views. * @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to. * @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if * parentID is an avatar skeleton. A value of 65535 means "no joint". @@ -259,6 +269,9 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "grabbable") { return _isGrabbable; } + if (property == "isVisibleInSecondaryCamera") { + return _isVisibleInSecondaryCamera; + } if (property == "parentID") { return getParentID(); } diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index bbf064fddd..8979081f7d 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -48,6 +48,7 @@ public: bool getDrawInFront() const { return _drawInFront; } bool getDrawHUDLayer() const { return _drawHUDLayer; } bool getIsGrabbable() const { return _isGrabbable; } + virtual bool getIsVisibleInSecondaryCamera() const override { return _isVisibleInSecondaryCamera; } void setIsSolid(bool isSolid) { _isSolid = isSolid; } void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; } @@ -55,6 +56,7 @@ public: virtual void setDrawInFront(bool value) { _drawInFront = value; } virtual void setDrawHUDLayer(bool value) { _drawHUDLayer = value; } void setIsGrabbable(bool value) { _isGrabbable = value; } + void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual AABox getBounds() const override = 0; @@ -92,6 +94,7 @@ protected: bool _drawInFront; bool _drawHUDLayer; bool _isGrabbable { false }; + bool _isVisibleInSecondaryCamera { false }; mutable bool _renderVariableDirty { true }; QString _name; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 651213ae99..88b95be2c0 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -90,7 +90,9 @@ void ModelOverlay::update(float deltatime) { if (_visibleDirty) { _visibleDirty = false; // don't show overlays in mirrors - _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0, false); + _model->setVisibleInScene(getVisible(), scene, + _isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_ALL : render::ItemKey::TAG_BITS_0, + false); } if (_drawInFrontDirty) { _drawInFrontDirty = false; diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index f1be23ed39..2f27d50f7e 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -56,6 +56,8 @@ public: bool isLoaded() { return _isLoaded; } bool getVisible() const { return _visible; } virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; }; + virtual bool getIsVisibleInSecondaryCamera() const { return false; } + xColor getColor(); float getAlpha(); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index f99ced0021..1317cae629 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -49,7 +49,11 @@ namespace render { builder.withInvisible(); } - builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view + uint32_t viewTaskBits = overlay->isVisibleInSecondaryCamera() ? + render::ItemKey::TAG_BITS_ALL : // draw in all views + render::ItemKey::TAG_BITS_0; // only the main view + + builder.withTagBits(viewTaskBits); return builder.build(); } From 602bc37b1a1a150ca15e9ac8af092bc608adbc69 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 13 Mar 2018 16:39:56 -0700 Subject: [PATCH 40/45] oops --- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 1317cae629..a86804d4c4 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -49,7 +49,7 @@ namespace render { builder.withInvisible(); } - uint32_t viewTaskBits = overlay->isVisibleInSecondaryCamera() ? + uint32_t viewTaskBits = overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_ALL : // draw in all views render::ItemKey::TAG_BITS_0; // only the main view From b22e0f6209176175c297c582c038a93bdef173ec Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 15 Mar 2018 09:55:42 -0700 Subject: [PATCH 41/45] use TAG_BITS_1 for cam rather than TAG_BITS_ALL --- interface/src/ui/overlays/ModelOverlay.cpp | 5 +++-- interface/src/ui/overlays/OverlaysPayload.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 88b95be2c0..7f19cf1fc7 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -89,9 +89,10 @@ void ModelOverlay::update(float deltatime) { } if (_visibleDirty) { _visibleDirty = false; - // don't show overlays in mirrors + // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true _model->setVisibleInScene(getVisible(), scene, - _isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_ALL : render::ItemKey::TAG_BITS_0, + render::ItemKey::TAG_BITS_0 | + _isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE, false); } if (_drawInFrontDirty) { diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index a86804d4c4..0a18acf447 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -49,9 +49,9 @@ namespace render { builder.withInvisible(); } - uint32_t viewTaskBits = overlay->getIsVisibleInSecondaryCamera() ? - render::ItemKey::TAG_BITS_ALL : // draw in all views - render::ItemKey::TAG_BITS_0; // only the main view + // always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view + uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 | + overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE; builder.withTagBits(viewTaskBits); From a5b94f22fa92c5decc13e2c26f0ebc26af72ef0b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 15 Mar 2018 10:31:55 -0700 Subject: [PATCH 42/45] works now --- interface/src/ui/overlays/Base3DOverlay.h | 2 +- interface/src/ui/overlays/ModelOverlay.cpp | 2 +- interface/src/ui/overlays/ModelOverlay.h | 5 +++++ interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 8979081f7d..ab83a64273 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -56,7 +56,7 @@ public: virtual void setDrawInFront(bool value) { _drawInFront = value; } virtual void setDrawHUDLayer(bool value) { _drawHUDLayer = value; } void setIsGrabbable(bool value) { _isGrabbable = value; } - void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } + virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual AABox getBounds() const override = 0; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 7f19cf1fc7..1c00f57eec 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -92,7 +92,7 @@ void ModelOverlay::update(float deltatime) { // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0 | - _isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE, + (_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE), false); } if (_drawInFrontDirty) { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 88a1729d68..3ef3f23fec 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -36,6 +36,11 @@ public: void clearSubRenderItemIDs(); void setSubRenderItemIDs(const render::ItemIDs& ids); + virtual void setIsVisibleInSecondaryCamera(bool value) override { + Base3DOverlay::setIsVisibleInSecondaryCamera(value); + _visibleDirty = true; + } + void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 0a18acf447..185547a333 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -51,7 +51,7 @@ namespace render { // always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 | - overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE; + (overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE); builder.withTagBits(viewTaskBits); From 8a0b8aa034df1b22282da00de4d549749766010e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 15 Mar 2018 11:01:13 -0700 Subject: [PATCH 43/45] make tablet invisible in secondary-camera if wallet passphrase page is up --- scripts/system/marketplaces/marketplaces.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index b3ca300022..f1a99500db 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -9,7 +9,8 @@ // /* global Tablet, Script, HMD, UserActivityLogger, Entities, Account, Wallet, ContextOverlay, Settings, Camera, Vec3, - Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow */ + Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow, Overlays, SoundCache, + DesktopPreviewProvider */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ var selectionDisplay = null; // for gridTool.js to ignore @@ -117,6 +118,13 @@ var selectionDisplay = null; // for gridTool.js to ignore var onWalletScreen = false; var onCommerceScreen = false; + function setTabletVisibleInSecondaryCamera(visibleInSecondaryCam) { + Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); + Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); + Overlays.editOverlay(HMD.homeButtonHighlightIDtabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); + Overlays.editOverlay(HMD.tabletScreenID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); + } + function onScreenChanged(type, url) { onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1; var onWalletScreenNow = url.indexOf(MARKETPLACE_WALLET_QML_PATH) !== -1; @@ -127,6 +135,7 @@ var selectionDisplay = null; // for gridTool.js to ignore if (isHmdPreviewDisabledBySecurity) { DesktopPreviewProvider.setPreviewDisabledReason("USER"); Menu.setIsOptionChecked("Disable Preview", false); + setTabletVisibleInSecondaryCamera(true); isHmdPreviewDisabledBySecurity = false; } } @@ -245,7 +254,7 @@ var selectionDisplay = null; // for gridTool.js to ignore var wearableDimensions = null; if (itemType === "contentSet") { - console.log("Item is a content set; codepath shouldn't go here.") + console.log("Item is a content set; codepath shouldn't go here."); return; } @@ -575,6 +584,7 @@ var selectionDisplay = null; // for gridTool.js to ignore if (!isHmdPreviewDisabled) { DesktopPreviewProvider.setPreviewDisabledReason("SECURE_SCREEN"); Menu.setIsOptionChecked("Disable Preview", true); + setTabletVisibleInSecondaryCamera(false); isHmdPreviewDisabledBySecurity = true; } break; @@ -582,6 +592,7 @@ var selectionDisplay = null; // for gridTool.js to ignore if (isHmdPreviewDisabledBySecurity) { DesktopPreviewProvider.setPreviewDisabledReason("USER"); Menu.setIsOptionChecked("Disable Preview", false); + setTabletVisibleInSecondaryCamera(true); isHmdPreviewDisabledBySecurity = false; } break; From a64f0d2779a6e928b36255d988d73240dff9086f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 15 Mar 2018 11:39:05 -0700 Subject: [PATCH 44/45] if tablet wasn't visible when wallet passphrase screen hid it, don't show it when passphrase page is done. --- scripts/system/marketplaces/marketplaces.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index f1a99500db..32dbe0a43b 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -117,8 +117,19 @@ var selectionDisplay = null; // for gridTool.js to ignore var onWalletScreen = false; var onCommerceScreen = false; + var tabletShouldBeVisibleInSecondaryCamera = false; function setTabletVisibleInSecondaryCamera(visibleInSecondaryCam) { + if (visibleInSecondaryCam) { + // if we're potentially showing the tablet, only do so if it was visible before + if (!tabletShouldBeVisibleInSecondaryCamera) { + return; + } + } else { + // if we're hiding the tablet, check to see if it was visible in the first place + tabletShouldBeVisibleInSecondaryCamera = Overlays.getProperty(HMD.tabletID, "isVisibleInSecondaryCamera"); + } + Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); Overlays.editOverlay(HMD.homeButtonHighlightIDtabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam }); From f6c4f6b9c4aa9494458244f7a752de884b66a6f4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 15 Mar 2018 13:06:27 -0700 Subject: [PATCH 45/45] Fix for arm IK jitter When in HMD mode, holding your hand controller in front of your face, would often result in a 1-2 mm pop in wrist position. This was due to a problem in the IK elbow constraint. When the swing rotation out of the elbow's reference frame was close to but not exactly identity it would not be properly constrainted. But when the magnitude of that swing became big enough the constraint would engage. This small change in swing rotation was noticable as a 1-2 mm movement in the wrist. --- libraries/animation/src/ElbowConstraint.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/animation/src/ElbowConstraint.cpp b/libraries/animation/src/ElbowConstraint.cpp index 17c6bb2da6..deaf1a0945 100644 --- a/libraries/animation/src/ElbowConstraint.cpp +++ b/libraries/animation/src/ElbowConstraint.cpp @@ -66,16 +66,12 @@ bool ElbowConstraint::apply(glm::quat& rotation) const { bool twistWasClamped = (twistAngle != clampedTwistAngle); // update rotation - const float MIN_SWING_REAL_PART = 0.99999f; - if (twistWasClamped || fabsf(swingRotation.w) < MIN_SWING_REAL_PART) { - if (twistWasClamped) { - twistRotation = glm::angleAxis(clampedTwistAngle, _axis); - } - // we discard all swing and only keep twist - rotation = twistRotation * _referenceRotation; - return true; + if (twistWasClamped) { + twistRotation = glm::angleAxis(clampedTwistAngle, _axis); } - return false; + // we discard all swing and only keep twist + rotation = twistRotation * _referenceRotation; + return true; } glm::quat ElbowConstraint::computeCenterRotation() const {