History

working on material baker

SamGondelman committed 7 years ago

Commit 94de0c11 parent 4965adb13 files · +492 −79Browse files

Unified · Split

13 files
  1. libraries/baking/CMakeLists.txt +1 −1
  2. libraries/baking/src/MaterialBaker.cpp +118 −0
  3. libraries/baking/src/MaterialBaker.h +58 −0
  4. libraries/baking/src/MaterialBakingLoggingCategory.cpp +14 −0
  5. libraries/baking/src/MaterialBakingLoggingCategory.h +19 −0
  6. libraries/graphics-scripting/src/graphics-scripting/Forward.h +2 −0
  7. libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +75 −14
  8. libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +60 −55
  9. tools/oven/CMakeLists.txt +1 −1
  10. tools/oven/src/BakerCLI.cpp +3 −2
  11. tools/oven/src/DomainBaker.cpp +133 −6
  12. tools/oven/src/DomainBaker.h +4 −0
  13. tools/oven/src/Oven.cpp +4 −0
libraries/baking/CMakeLists.txt+1−1
@@ -1,7 +1,7 @@
1set(TARGET_NAME baking)1set(TARGET_NAME baking)
2setup_hifi_library(Concurrent)2setup_hifi_library(Concurrent)
3 3
4link_hifi_libraries(shared graphics networking ktx image fbx)4link_hifi_libraries(shared shaders graphics networking material-networking ktx image fbx)
5include_hifi_library_headers(gpu)5include_hifi_library_headers(gpu)
6include_hifi_library_headers(hfm)6include_hifi_library_headers(hfm)
7 7
libraries/baking/src/MaterialBaker.cpp+118−0
@@ -0,0 +1,118 @@
1//
2// MaterialBaker.cpp
3// libraries/baking/src
4//
5// Created by Sam Gondelman on 2/26/2019
6// Copyright 2019 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include "MaterialBaker.h"
13
14#include "QJsonObject"
15#include "QJsonDocument"
16
17#include "MaterialBakingLoggingCategory.h"
18
19#include <SharedUtil.h>
20#include <PathUtils.h>
21
22MaterialBaker::MaterialBaker(const QString& materialData, bool isURL, const QString& bakedOutputDir) :
23 _materialData(materialData),
24 _isURL(isURL),
25 _bakedOutputDir(bakedOutputDir)
26{
27}
28
29void MaterialBaker::bake() {
30 qDebug(material_baking) << "Material Baker" << _materialData << "bake starting";
31
32 // once our script is loaded, kick off a the processing
33 connect(this, &MaterialBaker::originalMaterialLoaded, this, &MaterialBaker::processMaterial);
34
35 if (!_materialResource) {
36 // first load the material (either locally or remotely)
37 loadMaterial();
38 } else {
39 // we already have a material passed to us, use that
40 if (_materialResource->isLoaded()) {
41 emit originalMaterialLoaded();
42 } else {
43 connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded);
44 }
45 }
46}
47
48void MaterialBaker::loadMaterial() {
49 if (!_isURL) {
50 qCDebug(material_baking) << "Loading local material" << _materialData;
51
52 _materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource());
53 // TODO: add baseURL to allow these to reference relative files next to them
54 _materialResource->parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromVariant(_materialData), QUrl());
55 } else {
56 qCDebug(material_baking) << "Downloading material" << _materialData;
57 _materialResource = MaterialCache::instance().getMaterial(_materialData);
58 }
59
60 if (_materialResource) {
61 if (_materialResource->isLoaded()) {
62 emit originalMaterialLoaded();
63 } else {
64 connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded);
65 }
66 } else {
67 handleError("Error loading " + _materialData);
68 }
69}
70
71void MaterialBaker::processMaterial() {
72 if (!_materialResource || _materialResource->parsedMaterials.networkMaterials.size() == 0) {
73 handleError("Error processing " + _materialData);
74 }
75
76 _numTexturesToLoad = _materialResource->parsedMaterials.networkMaterials.size();
77 _numTexturesLoaded = 0;
78
79 for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) {
80 if (networkMaterial.second) {
81 auto textureMaps = networkMaterial.second->getTextureMaps();
82 for (auto textureMap : textureMaps) {
83 if (textureMap.second && textureMap.second->getTextureSource()) {
84 auto texture = textureMap.second->getTextureSource();
85 graphics::Material::MapChannel mapChannel = textureMap.first;
86
87 qDebug() << "boop" << mapChannel << texture->getUrl();
88 }
89 }
90 }
91 }
92}
93
94void MaterialBaker::outputMaterial() {
95 //if (_isURL) {
96 // auto fileName = _materialData;
97 // auto baseName = fileName.left(fileName.lastIndexOf('.'));
98 // auto bakedFilename = baseName + BAKED_MATERIAL_EXTENSION;
99
100 // _bakedMaterialData = _bakedOutputDir + "/" + bakedFilename;
101
102 // QFile bakedFile;
103 // bakedFile.setFileName(_bakedMaterialData);
104 // if (!bakedFile.open(QIODevice::WriteOnly)) {
105 // handleError("Error opening " + _bakedMaterialData + " for writing");
106 // return;
107 // }
108
109 // bakedFile.write(outputMaterial);
110
111 // // Export successful
112 // _outputFiles.push_back(_bakedMaterialData);
113 // qCDebug(material_baking) << "Exported" << _materialData << "to" << _bakedMaterialData;
114 //}
115
116 // emit signal to indicate the material baking is finished
117 emit finished();
118}
libraries/baking/src/MaterialBaker.h+58−0
@@ -0,0 +1,58 @@
1//
2// MaterialBaker.h
3// libraries/baking/src
4//
5// Created by Sam Gondelman on 2/26/2019
6// Copyright 2019 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_MaterialBaker_h
13#define hifi_MaterialBaker_h
14
15#include "Baker.h"
16
17#include "TextureBaker.h"
18
19#include <material-networking/MaterialCache.h>
20
21static const QString BAKED_MATERIAL_EXTENSION = ".baked.json";
22
23class MaterialBaker : public Baker {
24 Q_OBJECT
25public:
26 MaterialBaker(const QString& materialData, bool isURL, const QString& bakedOutputDir);
27
28 QString getMaterialData() const { return _materialData; }
29 bool isURL() const { return _isURL; }
30 QString getBakedMaterialData() const { return _bakedMaterialData; }
31
32public slots:
33 virtual void bake() override;
34
35signals:
36 void originalMaterialLoaded();
37
38private slots:
39 void processMaterial();
40 void outputMaterial();
41
42private:
43 void loadMaterial();
44
45 QString _materialData;
46 bool _isURL;
47
48 NetworkMaterialResourcePointer _materialResource;
49 size_t _numTexturesToLoad { 0 };
50 size_t _numTexturesLoaded { 0 };
51
52 QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;
53
54 QString _bakedOutputDir;
55 QString _bakedMaterialData;
56};
57
58#endif // !hifi_MaterialBaker_h
libraries/baking/src/MaterialBakingLoggingCategory.cpp+14−0
@@ -0,0 +1,14 @@
1//
2// MaterialBakingLoggingCategory.cpp
3// libraries/baking/src
4//
5// Created by Sam Gondelman on 2/26/2019
6// Copyright 2019 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include "MaterialBakingLoggingCategory.h"
13
14Q_LOGGING_CATEGORY(material_baking, "hifi.material-baking");
libraries/baking/src/MaterialBakingLoggingCategory.h+19−0
@@ -0,0 +1,19 @@
1//
2// MaterialBakingLoggingCategory.h
3// libraries/baking/src
4//
5// Created by Sam Gondelman on 2/26/2019
6// Copyright 2019 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_MaterialBakingLoggingCategory_h
13#define hifi_MaterialBakingLoggingCategory_h
14
15#include <QtCore/QLoggingCategory>
16
17Q_DECLARE_LOGGING_CATEGORY(material_baking)
18
19#endif // hifi_MaterialBakingLoggingCategory_h
libraries/graphics-scripting/src/graphics-scripting/Forward.h+2−0
@@ -96,6 +96,8 @@ namespace scriptable { · 95 unmodified lines
96 96
97 bool defaultFallthrough;97 bool defaultFallthrough;
98 std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script98 std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script
99
100 graphics::MaterialKey key { 0 };
99 };101 };
100 102
101 /**jsdoc103 /**jsdoc
libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp+75−14
@@ -364,20 +364,81 @@ namespace scriptable { · 363 unmodified lines
364 obj.setProperty("model", material.model);364 obj.setProperty("model", material.model);
365 365
366 const QScriptValue FALLTHROUGH("fallthrough");366 const QScriptValue FALLTHROUGH("fallthrough");
367 obj.setProperty("opacity", material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT) ? FALLTHROUGH : material.opacity);367 if (material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT)) {
368 obj.setProperty("roughness", material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT) ? FALLTHROUGH : material.roughness);368 obj.setProperty("opacity", FALLTHROUGH);
369 obj.setProperty("metallic", material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT) ? FALLTHROUGH : material.metallic);369 } else if (material.key.isTranslucentFactor()) {
370 obj.setProperty("scattering", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT) ? FALLTHROUGH : material.scattering);370 obj.setProperty("opacity", material.opacity);
371 obj.setProperty("unlit", material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT) ? FALLTHROUGH : material.unlit);371 }
372 obj.setProperty("emissive", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.emissive));372
373 obj.setProperty("albedo", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.albedo));373 if (material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) {
374 374 obj.setProperty("roughness", FALLTHROUGH);
375 obj.setProperty("emissiveMap", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT) ? FALLTHROUGH : material.emissiveMap);375 } else if (material.key.isGlossy()) {
376 obj.setProperty("albedoMap", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT) ? FALLTHROUGH : material.albedoMap);376 obj.setProperty("roughness", material.roughness);
377 obj.setProperty("opacityMap", material.opacityMap);377 }
378 obj.setProperty("occlusionMap", material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT) ? FALLTHROUGH : material.occlusionMap);378
379 obj.setProperty("lightmapMap", material.propertyFallthroughs.at(graphics::MaterialKey::LIGHTMAP_MAP_BIT) ? FALLTHROUGH : material.lightmapMap);379 if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) {
380 obj.setProperty("scatteringMap", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT) ? FALLTHROUGH : material.scatteringMap);380 obj.setProperty("metallic", FALLTHROUGH);
381 } else if (material.key.isMetallic()) {
382 obj.setProperty("metallic", material.metallic);
383 }
384
385 if (material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) {
386 obj.setProperty("scattering", FALLTHROUGH);
387 } else if (material.key.isScattering()) {
388 obj.setProperty("scattering", material.scattering);
389 }
390
391 if (material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) {
392 obj.setProperty("unlit", FALLTHROUGH);
393 } else if (material.key.isUnlit()) {
394 obj.setProperty("unlit", material.unlit);
395 }
396
397 if (material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) {
398 obj.setProperty("emissive", FALLTHROUGH);
399 } else if (material.key.isEmissive()) {
400 obj.setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive));
401 }
402
403 if (material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT)) {
404 obj.setProperty("albedo", FALLTHROUGH);
405 } else if (material.key.isAlbedo()) {
406 obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo));
407 }
408
409 if (material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT)) {
410 obj.setProperty("emissiveMap", FALLTHROUGH);
411 } else if (!material.emissiveMap.isEmpty()) {
412 obj.setProperty("emissiveMap", material.emissiveMap);
413 }
414
415 if (material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT)) {
416 obj.setProperty("albedoMap", FALLTHROUGH);
417 } else if (!material.albedoMap.isEmpty()) {
418 obj.setProperty("albedoMap", material.albedoMap);
419 }
420
421 if (!material.opacityMap.isEmpty()) {
422 obj.setProperty("opacityMap", material.opacityMap);
423 }
424
425 if (material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
426 obj.setProperty("occlusionMap", FALLTHROUGH);
427 } else if (!material.occlusionMap.isEmpty()) {
428 obj.setProperty("occlusionMap", material.occlusionMap);
429 }
430
431 if (material.propertyFallthroughs.at(graphics::MaterialKey::LIGHTMAP_MAP_BIT)) {
432 obj.setProperty("lightmapMap", FALLTHROUGH);
433 } else if (!material.lightmapMap.isEmpty()) {
434 obj.setProperty("lightmapMap", material.lightmapMap);
435 }
436
437 if (material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
438 obj.setProperty("scatteringMap", FALLTHROUGH);
439 } else if (!material.scatteringMap.isEmpty()) {
440 obj.setProperty("scatteringMap", material.scatteringMap);
441 }
381 442
382 // Only set one of each of these443 // Only set one of each of these
383 if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {444 if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {
libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp+60−55
@@ -45,75 +45,80 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const · 44 unmodified lines
45 defaultFallthrough = material.defaultFallthrough;45 defaultFallthrough = material.defaultFallthrough;
46 propertyFallthroughs = material.propertyFallthroughs;46 propertyFallthroughs = material.propertyFallthroughs;
47 47
48 key = material.key;
49
48 return *this;50 return *this;
49}51}
50 52
51scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) :53scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) {
52 name(material->getName().c_str()),54 if (material) {
53 model(material->getModel().c_str()),55 name = material->getName().c_str();
54 opacity(material->getOpacity()),56 model = material->getModel().c_str();
55 roughness(material->getRoughness()),57 opacity = material->getOpacity();
56 metallic(material->getMetallic()),58 roughness = material->getRoughness();
57 scattering(material->getScattering()),59 metallic = material->getMetallic();
58 unlit(material->isUnlit()),60 scattering = material->getScattering();
59 emissive(material->getEmissive()),61 unlit = material->isUnlit();
60 albedo(material->getAlbedo()),62 emissive = material->getEmissive();
61 defaultFallthrough(material->getDefaultFallthrough()),63 albedo = material->getAlbedo();
62 propertyFallthroughs(material->getPropertyFallthroughs())64 defaultFallthrough = material->getDefaultFallthrough();
63{65 propertyFallthroughs = material->getPropertyFallthroughs();
64 auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);66 key = material->getKey();
65 if (map && map->getTextureSource()) {67
66 emissiveMap = map->getTextureSource()->getUrl().toString();68 auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
67 }69 if (map && map->getTextureSource()) {
70 emissiveMap = map->getTextureSource()->getUrl().toString();
71 }
68 72
69 map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP);73 map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP);
70 if (map && map->getTextureSource()) {74 if (map && map->getTextureSource()) {
71 albedoMap = map->getTextureSource()->getUrl().toString();75 albedoMap = map->getTextureSource()->getUrl().toString();
72 if (map->useAlphaChannel()) {76 if (map->useAlphaChannel()) {
73 opacityMap = albedoMap;77 opacityMap = albedoMap;
78 }
74 }79 }
75 }
76 80
77 map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);81 map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);
78 if (map && map->getTextureSource()) {82 if (map && map->getTextureSource()) {
79 if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) {83 if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) {
80 metallicMap = map->getTextureSource()->getUrl().toString();84 metallicMap = map->getTextureSource()->getUrl().toString();
81 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) {85 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) {
82 specularMap = map->getTextureSource()->getUrl().toString();86 specularMap = map->getTextureSource()->getUrl().toString();
87 }
83 }88 }
84 }
85 89
86 map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);90 map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);
87 if (map && map->getTextureSource()) {91 if (map && map->getTextureSource()) {
88 if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) {92 if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) {
89 roughnessMap = map->getTextureSource()->getUrl().toString();93 roughnessMap = map->getTextureSource()->getUrl().toString();
90 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) {94 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) {
91 glossMap = map->getTextureSource()->getUrl().toString();95 glossMap = map->getTextureSource()->getUrl().toString();
96 }
92 }97 }
93 }
94 98
95 map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);99 map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);
96 if (map && map->getTextureSource()) {100 if (map && map->getTextureSource()) {
97 if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {101 if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {
98 normalMap = map->getTextureSource()->getUrl().toString();102 normalMap = map->getTextureSource()->getUrl().toString();
99 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) {103 } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) {
100 bumpMap = map->getTextureSource()->getUrl().toString();104 bumpMap = map->getTextureSource()->getUrl().toString();
105 }
101 }106 }
102 }
103 107
104 map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);108 map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
105 if (map && map->getTextureSource()) {109 if (map && map->getTextureSource()) {
106 occlusionMap = map->getTextureSource()->getUrl().toString();110 occlusionMap = map->getTextureSource()->getUrl().toString();
107 }111 }
108 112
109 map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP);113 map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP);
110 if (map && map->getTextureSource()) {114 if (map && map->getTextureSource()) {
111 lightmapMap = map->getTextureSource()->getUrl().toString();115 lightmapMap = map->getTextureSource()->getUrl().toString();
112 }116 }
113 117
114 map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);118 map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
115 if (map && map->getTextureSource()) {119 if (map && map->getTextureSource()) {
116 scatteringMap = map->getTextureSource()->getUrl().toString();120 scatteringMap = map->getTextureSource()->getUrl().toString();
121 }
117 }122 }
118}123}
119 124
tools/oven/CMakeLists.txt+1−1
@@ -2,7 +2,7 @@ set(TARGET_NAME oven) · 1 unmodified line
2 2
3setup_hifi_project(Widgets Gui Concurrent)3setup_hifi_project(Widgets Gui Concurrent)
4 4
5link_hifi_libraries(networking shared image gpu ktx fbx hfm baking graphics)5link_hifi_libraries(shared shaders image gpu ktx fbx hfm baking graphics networking material-networking)
6 6
7setup_memory_debugger()7setup_memory_debugger()
8 8
tools/oven/src/BakerCLI.cpp+3−2
@@ -23,6 +23,7 @@ · 22 unmodified lines
23#include "baking/BakerLibrary.h"23#include "baking/BakerLibrary.h"
24#include "JSBaker.h"24#include "JSBaker.h"
25#include "TextureBaker.h"25#include "TextureBaker.h"
26#include "MaterialBaker.h"
26 27
27BakerCLI::BakerCLI(OvenCLIApplication* parent) : QObject(parent) {28BakerCLI::BakerCLI(OvenCLIApplication* parent) : QObject(parent) {
28 29
@@ -60,8 +61,8 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString& · 31 unmodified lines
60 _baker = std::unique_ptr<Baker> { new JSBaker(inputUrl, outputPath) };61 _baker = std::unique_ptr<Baker> { new JSBaker(inputUrl, outputPath) };
61 _baker->moveToThread(Oven::instance().getNextWorkerThread());62 _baker->moveToThread(Oven::instance().getNextWorkerThread());
62 } else if (type == MATERIAL_EXTENSION) {63 } else if (type == MATERIAL_EXTENSION) {
63 //_baker = std::unique_ptr<Baker> { new MaterialBaker(inputUrl, outputPath) };64 _baker = std::unique_ptr<Baker> { new MaterialBaker(inputUrl.toDisplayString(), true, outputPath) };
64 //_baker->moveToThread(Oven::instance().getNextWorkerThread());65 _baker->moveToThread(Oven::instance().getNextWorkerThread());
65 } else {66 } else {
66 // If the type doesn't match the above, we assume we have a texture, and the type specified is the67 // If the type doesn't match the above, we assume we have a texture, and the type specified is the
67 // texture usage type (albedo, cubemap, normals, etc.)68 // texture usage type (albedo, cubemap, normals, etc.)
tools/oven/src/DomainBaker.cpp+133−6
@@ -187,8 +187,8 @@ void DomainBaker::addTextureBaker(const QString& property, const QString& url, i · 186 unmodified lines
187 187
188 // setup a texture baker for this URL, as long as we aren't baking a texture already188 // setup a texture baker for this URL, as long as we aren't baking a texture already
189 if (!_textureBakers.contains(textureURL)) {189 if (!_textureBakers.contains(textureURL)) {
190 // setup a baker for this texture
191 190
191 // setup a baker for this texture
192 QSharedPointer<TextureBaker> textureBaker {192 QSharedPointer<TextureBaker> textureBaker {
193 new TextureBaker(textureURL, type, _contentOutputPath),193 new TextureBaker(textureURL, type, _contentOutputPath),
194 &TextureBaker::deleteLater194 &TextureBaker::deleteLater
@@ -220,16 +220,16 @@ void DomainBaker::addScriptBaker(const QString& property, const QString& url, QJ · 25 unmodified lines
220 // grab a clean version of the URL without a query or fragment220 // grab a clean version of the URL without a query or fragment
221 QUrl scriptURL = QUrl(url).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);221 QUrl scriptURL = QUrl(url).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
222 222
223 // setup a texture baker for this URL, as long as we aren't baking a texture already223 // setup a script baker for this URL, as long as we aren't baking a texture already
224 if (!_scriptBakers.contains(scriptURL)) {224 if (!_scriptBakers.contains(scriptURL)) {
225 // setup a baker for this texture
226 225
226 // setup a baker for this script
227 QSharedPointer<JSBaker> scriptBaker {227 QSharedPointer<JSBaker> scriptBaker {
228 new JSBaker(scriptURL, _contentOutputPath),228 new JSBaker(scriptURL, _contentOutputPath),
229 &JSBaker::deleteLater229 &JSBaker::deleteLater
230 };230 };
231 231
232 // make sure our handler is called when the texture baker is done232 // make sure our handler is called when the script baker is done
233 connect(scriptBaker.data(), &JSBaker::finished, this, &DomainBaker::handleFinishedScriptBaker);233 connect(scriptBaker.data(), &JSBaker::finished, this, &DomainBaker::handleFinishedScriptBaker);
234 234
235 // insert it into our bakers hash so we hold a strong pointer to it235 // insert it into our bakers hash so we hold a strong pointer to it
@@ -243,11 +243,48 @@ void DomainBaker::addScriptBaker(const QString& property, const QString& url, QJ · 7 unmodified lines
243 ++_totalNumberOfSubBakes;243 ++_totalNumberOfSubBakes;
244 }244 }
245 245
246 // add this QJsonValueRef to our multi hash so that it can re-write the texture URL246 // add this QJsonValueRef to our multi hash so that it can re-write the script URL
247 // to the baked version once the baker is complete247 // to the baked version once the baker is complete
248 _entitiesNeedingRewrite.insert(scriptURL, { property, jsonRef });248 _entitiesNeedingRewrite.insert(scriptURL, { property, jsonRef });
249}249}
250 250
251void DomainBaker::addMaterialBaker(const QString& property, const QString& data, bool isURL, QJsonValueRef& jsonRef) {
252 // grab a clean version of the URL without a query or fragment
253 QString materialData;
254 if (isURL) {
255 materialData = QUrl(data).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment).toDisplayString();
256 } else {
257 materialData = data;
258 }
259
260 // setup a material baker for this URL, as long as we aren't baking a material already
261 if (!_materialBakers.contains(materialData)) {
262
263 // setup a baker for this material
264 QSharedPointer<MaterialBaker> materialBaker {
265 new MaterialBaker(data, isURL, _contentOutputPath),
266 &MaterialBaker::deleteLater
267 };
268
269 // make sure our handler is called when the material baker is done
270 connect(materialBaker.data(), &MaterialBaker::finished, this, &DomainBaker::handleFinishedMaterialBaker);
271
272 // insert it into our bakers hash so we hold a strong pointer to it
273 _materialBakers.insert(materialData, materialBaker);
274
275 // move the baker to a worker thread and kickoff the bake
276 materialBaker->moveToThread(Oven::instance().getNextWorkerThread());
277 QMetaObject::invokeMethod(materialBaker.data(), "bake");
278
279 // keep track of the total number of baking entities
280 ++_totalNumberOfSubBakes;
281 }
282
283 // add this QJsonValueRef to our multi hash so that it can re-write the texture URL
284 // to the baked version once the baker is complete
285 _entitiesNeedingRewrite.insert(materialData, { property, jsonRef });
286}
287
251// All the Entity Properties that can be baked288// All the Entity Properties that can be baked
252// ***************************************************************************************289// ***************************************************************************************
253 290
@@ -348,7 +385,12 @@ void DomainBaker::enumerateEntities() { · 94 unmodified lines
348 }385 }
349 386
350 // Materials387 // Materials
351 // TODO388 if (entity.contains(MATERIAL_URL_KEY)) {
389 addMaterialBaker(MATERIAL_URL_KEY, entity[MATERIAL_URL_KEY].toString(), true, *it);
390 }
391 if (entity.contains(MATERIAL_DATA_KEY)) {
392 addMaterialBaker(MATERIAL_DATA_KEY, entity[MATERIAL_URL_KEY].toString(), false, *it);
393 }
352 }394 }
353 }395 }
354 396
@@ -568,6 +610,91 @@ void DomainBaker::handleFinishedScriptBaker() { · 213 unmodified lines
568 }610 }
569}611}
570 612
613void DomainBaker::handleFinishedMaterialBaker() {
614 auto baker = qobject_cast<MaterialBaker*>(sender());
615
616 if (baker) {
617 if (!baker->hasErrors()) {
618 // this MaterialBaker is done and everything went according to plan
619 qDebug() << "Re-writing entity references to" << baker->getMaterialData();
620
621 QString newDataOrURL;
622 if (baker->isURL()) {
623 newDataOrURL = _destinationPath.resolved(baker->getBakedMaterialData()).toDisplayString();
624 } else {
625 newDataOrURL = baker->getBakedMaterialData();
626 }
627
628 // enumerate the QJsonRef values for the URL of this material from our multi hash of
629 // entity objects needing a URL re-write
630 for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getMaterialData())) {
631 QString property = propertyEntityPair.first;
632 // convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
633 auto entity = propertyEntityPair.second.toObject();
634
635 if (!property.contains(".")) {
636 // grab the old URL
637 QUrl oldURL = entity[property].toString();
638
639 // copy the fragment and query, and user info from the old material data
640 if (baker->isURL()) {
641 QUrl newURL = newDataOrURL;
642 newURL.setQuery(oldURL.query());
643 newURL.setFragment(oldURL.fragment());
644 newURL.setUserInfo(oldURL.userInfo());
645
646 // set the new URL as the value in our temp QJsonObject
647 entity[property] = newURL.toString();
648 } else {
649 entity[property] = newDataOrURL;
650 }
651 } else {
652 // Group property
653 QStringList propertySplit = property.split(".");
654 assert(propertySplit.length() == 2);
655 // grab the old URL
656 auto oldObject = entity[propertySplit[0]].toObject();
657 QUrl oldURL = oldObject[propertySplit[1]].toString();
658
659 // copy the fragment and query, and user info from the old material data
660 if (baker->isURL()) {
661 QUrl newURL = newDataOrURL;
662 newURL.setQuery(oldURL.query());
663 newURL.setFragment(oldURL.fragment());
664 newURL.setUserInfo(oldURL.userInfo());
665
666 // set the new URL as the value in our temp QJsonObject
667 oldObject[propertySplit[1]] = newURL.toString();
668 entity[propertySplit[0]] = oldObject;
669 } else {
670 oldObject[propertySplit[1]] = newDataOrURL;
671 entity[propertySplit[0]] = oldObject;
672 }
673 }
674
675 // replace our temp object with the value referenced by our QJsonValueRef
676 propertyEntityPair.second = entity;
677 }
678 } else {
679 // this material failed to bake - this doesn't fail the entire bake but we need to add
680 // the errors from the material to our warnings
681 _warningList << baker->getErrors();
682 }
683
684 // remove the baked URL from the multi hash of entities needing a re-write
685 _entitiesNeedingRewrite.remove(baker->getMaterialData());
686
687 // drop our shared pointer to this baker so that it gets cleaned up
688 _materialBakers.remove(baker->getMaterialData());
689
690 // emit progress to tell listeners how many materials we have baked
691 emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
692
693 // check if this was the last material we needed to re-write and if we are done now
694 checkIfRewritingComplete();
695 }
696}
697
571void DomainBaker::checkIfRewritingComplete() {698void DomainBaker::checkIfRewritingComplete() {
572 if (_entitiesNeedingRewrite.isEmpty()) {699 if (_entitiesNeedingRewrite.isEmpty()) {
573 writeNewEntitiesFile();700 writeNewEntitiesFile();
tools/oven/src/DomainBaker.h+4−0
@@ -21,6 +21,7 @@ · 20 unmodified lines
21#include "ModelBaker.h"21#include "ModelBaker.h"
22#include "TextureBaker.h"22#include "TextureBaker.h"
23#include "JSBaker.h"23#include "JSBaker.h"
24#include "MaterialBaker.h"
24 25
25class DomainBaker : public Baker {26class DomainBaker : public Baker {
26 Q_OBJECT27 Q_OBJECT
@@ -40,6 +41,7 @@ private slots: · 13 unmodified lines
40 void handleFinishedModelBaker();41 void handleFinishedModelBaker();
41 void handleFinishedTextureBaker();42 void handleFinishedTextureBaker();
42 void handleFinishedScriptBaker();43 void handleFinishedScriptBaker();
44 void handleFinishedMaterialBaker();
43 45
44private:46private:
45 void setupOutputFolder();47 void setupOutputFolder();
@@ -62,6 +64,7 @@ private: · 16 unmodified lines
62 QHash<QUrl, QSharedPointer<ModelBaker>> _modelBakers;64 QHash<QUrl, QSharedPointer<ModelBaker>> _modelBakers;
63 QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;65 QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;
64 QHash<QUrl, QSharedPointer<JSBaker>> _scriptBakers;66 QHash<QUrl, QSharedPointer<JSBaker>> _scriptBakers;
67 QHash<QUrl, QSharedPointer<MaterialBaker>> _materialBakers;
65 68
66 QMultiHash<QUrl, std::pair<QString, QJsonValueRef>> _entitiesNeedingRewrite;69 QMultiHash<QUrl, std::pair<QString, QJsonValueRef>> _entitiesNeedingRewrite;
67 70
@@ -71,6 +74,7 @@ private: · 3 unmodified lines
71 void addModelBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);74 void addModelBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
72 void addTextureBaker(const QString& property, const QString& url, image::TextureUsage::Type type, QJsonValueRef& jsonRef);75 void addTextureBaker(const QString& property, const QString& url, image::TextureUsage::Type type, QJsonValueRef& jsonRef);
73 void addScriptBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);76 void addScriptBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
77 void addMaterialBaker(const QString& property, const QString& data, bool isURL, QJsonValueRef& jsonRef);
74};78};
75 79
76#endif // hifi_DomainBaker_h80#endif // hifi_DomainBaker_h
tools/oven/src/Oven.cpp+4−0
@@ -63,6 +63,10 @@ void Oven::setupWorkerThreads(int numWorkerThreads) { · 62 unmodified lines
63}63}
64 64
65QThread* Oven::getNextWorkerThread() {65QThread* Oven::getNextWorkerThread() {
66 // FIXME: we assign these threads when we make the bakers, but if certain bakers finish quickly, we could end up
67 // in a situation where threads have finished and others have tons of work queued. Instead of assigning them at initialization,
68 // we should build a queue of bakers, and when threads finish, they can take the next available baker.
69
66 // Here we replicate some of the functionality of QThreadPool by giving callers an available worker thread to use.70 // Here we replicate some of the functionality of QThreadPool by giving callers an available worker thread to use.
67 // We can't use QThreadPool because we want to put QObjects with signals/slots on these threads.71 // We can't use QThreadPool because we want to put QObjects with signals/slots on these threads.
68 // So instead we setup our own list of threads, up to one less than the ideal thread count72 // So instead we setup our own list of threads, up to one less than the ideal thread count