1
/***************************************************************************
2
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
4
* This file is part of FreeCAD. *
6
* FreeCAD is free software: you can redistribute it and/or modify it *
7
* under the terms of the GNU Lesser General Public License as *
8
* published by the Free Software Foundation, either version 2.1 of the *
9
* License, or (at your option) any later version. *
11
* FreeCAD is distributed in the hope that it will be useful, but *
12
* WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14
* Lesser General Public License for more details. *
16
* You should have received a copy of the GNU Lesser General Public *
17
* License along with FreeCAD. If not, see *
18
* <https://www.gnu.org/licenses/>. *
20
**************************************************************************/
22
#include "PreCompiled.h"
24
#include <QDirIterator>
36
#include <App/Application.h>
37
#include <Base/Interpreter.h>
40
#include "Exceptions.h"
41
#include "MaterialConfigLoader.h"
42
#include "MaterialLoader.h"
44
#include "ModelUuids.h"
47
using namespace Materials;
49
bool MaterialConfigLoader::isConfigStyle(const QString& path)
51
QSettings fcmat(path, QSettings::IniFormat);
53
// No [sections] means not .ini
54
if (fcmat.childGroups().empty()) {
58
// Sometimes arrays can create a false positive
60
if (infile.open(QIODevice::ReadOnly)) {
61
QTextStream in(&infile);
64
auto line = in.readLine();
65
if (line.trimmed().startsWith(QLatin1Char('-'))
66
|| line.trimmed().startsWith(QLatin1Char('#'))) {
67
// Definitely a YAML file
78
bool MaterialConfigLoader::readFile(const QString& path, QMap<QString, QString>& map)
80
// This function is necessary as the built in routines don't always return the full value string
82
if (infile.open(QIODevice::ReadOnly)) {
83
QTextStream in(&infile);
84
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
91
if (line.trimmed().startsWith(QLatin1Char(';'))) {
95
if (line.startsWith(QLatin1Char('['))) {
97
auto end = line.indexOf(QLatin1Char(']'));
99
prefix = line.mid(1, end - 1) + QString::fromStdString("/");
101
// Render WB uses both Render and Rendering
102
if (prefix == QString::fromStdString("Rendering/")) {
103
prefix = QString::fromStdString("Render/");
108
auto separator = line.indexOf(QLatin1Char('='));
110
auto left = line.mid(0, separator - 1);
111
auto right = line.mid(separator + 2);
112
map[prefix + left] = right;
123
void MaterialConfigLoader::splitTexture(const QString& value, QString* texture, QString* remain)
125
// Split Texture(...);(...) into its two pieces
126
if (value.contains(QLatin1Char(';'))) {
127
auto separator = value.indexOf(QLatin1Char(';'));
128
auto left = value.mid(0, separator);
129
auto right = value.mid(separator + 1);
130
if (isTexture(left)) {
140
if (isTexture(value)) {
149
void MaterialConfigLoader::splitTextureObject(const QString& value,
154
splitTexture(value, texture, remain);
155
if (*remain == QString::fromStdString("Object")) {
156
*remain = QString(); // Empty string
157
*object = QString::fromStdString("true");
161
QString MaterialConfigLoader::getAuthorAndLicense(const QString& path)
163
std::ifstream infile(path.toStdString());
166
// Skip the first line
168
if (!std::getline(infile, line)) {
172
// The second line has it in a comment
173
if (!std::getline(infile, line)) {
176
std::size_t found = line.find(';');
177
if (found != std::string::npos) {
178
return QString::fromStdString(trim_copy(line.substr(found + 1)));
184
void MaterialConfigLoader::addVectorRendering(const QMap<QString, QString>& fcmat,
185
const std::shared_ptr<Material>& finalModel)
187
QString sectionFillPattern = value(fcmat, "VectorRendering/SectionFillPattern", "");
188
QString sectionLinewidth = value(fcmat, "VectorRendering/SectionLinewidth", "");
189
QString sectionColor = value(fcmat, "VectorRendering/SectionColor", "");
190
QString viewColor = value(fcmat, "VectorRendering/ViewColor", "");
191
QString viewFillPattern = value(fcmat, "VectorRendering/ViewFillPattern", "");
192
QString viewLinewidth = value(fcmat, "VectorRendering/ViewLinewidth", "");
194
// Defined by the Render WB
195
QString aSection = value(fcmat, "Architectural/SectionColor", "");
197
if (!aSection.isEmpty()) {
198
sectionColor = aSection;
201
if (sectionFillPattern.length() + sectionLinewidth.length() + sectionColor.length()
202
+ viewColor.length() + viewFillPattern.length() + viewLinewidth.length()
204
finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Vector);
207
setAppearanceValue(finalModel, "SectionFillPattern", sectionFillPattern);
208
setAppearanceValue(finalModel, "SectionLinewidth", sectionLinewidth);
209
setAppearanceValue(finalModel, "SectionColor", sectionColor);
210
setAppearanceValue(finalModel, "ViewColor", viewColor);
211
setAppearanceValue(finalModel, "ViewFillPattern", viewFillPattern);
212
setAppearanceValue(finalModel, "ViewLinewidth", viewLinewidth);
216
void MaterialConfigLoader::addRendering(const QMap<QString, QString>& fcmat,
217
const std::shared_ptr<Material>& finalModel)
219
QString ambientColor = value(fcmat, "Rendering/AmbientColor", "");
220
QString diffuseColor = value(fcmat, "Rendering/DiffuseColor", "");
221
QString emissiveColor = value(fcmat, "Rendering/EmissiveColor", "");
222
QString shininess = value(fcmat, "Rendering/Shininess", "");
223
QString specularColor = value(fcmat, "Rendering/SpecularColor", "");
224
QString transparency = value(fcmat, "Rendering/Transparency", "");
225
QString texturePath = value(fcmat, "Rendering/TexturePath", "");
226
QString textureScaling = value(fcmat, "Rendering/TextureScaling", "");
227
QString fragmentShader = value(fcmat, "Rendering/FragmentShader", "");
228
QString vertexShader = value(fcmat, "Rendering/VertexShader", "");
230
// Defined by the Render WB
231
QString aDiffuse = value(fcmat, "Architectural/DiffuseColor", "");
232
QString aTransparency = value(fcmat, "Architectural/Transparency", "");
234
if (!aDiffuse.isEmpty()) {
235
diffuseColor = aDiffuse;
237
if (!aTransparency.isEmpty()) {
238
transparency = aTransparency;
241
// Check which model we need
242
bool useTexture = false;
243
bool useAdvanced = false;
244
bool useBasic = false;
245
if (texturePath.length() + textureScaling.length() > 0) {
248
if (fragmentShader.length() + vertexShader.length() > 0) {
251
if (ambientColor.length() + diffuseColor.length() + emissiveColor.length() + shininess.length()
252
+ specularColor.length() + transparency.length()
258
finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Advanced);
260
else if (useTexture) {
261
finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Texture);
264
finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic);
268
setAppearanceValue(finalModel, "AmbientColor", ambientColor);
269
setAppearanceValue(finalModel, "DiffuseColor", diffuseColor);
270
setAppearanceValue(finalModel, "EmissiveColor", emissiveColor);
271
setAppearanceValue(finalModel, "Shininess", shininess);
272
setAppearanceValue(finalModel, "SpecularColor", specularColor);
273
setAppearanceValue(finalModel, "Transparency", transparency);
274
setAppearanceValue(finalModel, "TexturePath", texturePath);
275
setAppearanceValue(finalModel, "TextureScaling", textureScaling);
276
setAppearanceValue(finalModel, "FragmentShader", fragmentShader);
277
setAppearanceValue(finalModel, "VertexShader", vertexShader);
280
QString MaterialConfigLoader::multiLineKey(QMap<QString, QString>& fcmat, const QString& prefix)
282
// fcmat.beginGroup(QString::fromStdString("Render"));
283
QString multiLineString;
284
auto keys = fcmat.keys();
285
for (const auto& key : keys) {
286
if (key.startsWith(prefix) || key.startsWith(QString::fromStdString("Render/") + prefix)) {
287
QString string = value(fcmat, key.toStdString(), "");
288
if (multiLineString.isEmpty()) {
289
multiLineString += string;
292
multiLineString += QString::fromStdString("\n") + string;
298
return multiLineString;
301
void MaterialConfigLoader::addRenderAppleseed(QMap<QString, QString>& fcmat,
302
const std::shared_ptr<Material>& finalModel)
304
QString prefix = QString::fromStdString("Render.Appleseed");
305
QString string = multiLineKey(fcmat, prefix);
307
if (!string.isEmpty()) {
308
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Appleseed);
311
setAppearanceValue(finalModel, "Render.Appleseed", string);
315
void MaterialConfigLoader::addRenderCarpaint(QMap<QString, QString>& fcmat,
316
const std::shared_ptr<Material>& finalModel)
318
QString renderBaseColorValue = value(fcmat, "Render/Render.Carpaint.BaseColor", "");
319
QString renderBump = value(fcmat, "Render/Render.Carpaint.Bump", "");
320
QString renderDisplacement = value(fcmat, "Render/Render.Carpaint.Displacement", "");
321
QString renderNormal = value(fcmat, "Render/Render.Carpaint.Normal", "");
323
// Split out the textures
324
QString renderBaseColor;
325
QString renderBaseColorTexture;
326
QString renderBaseColorObject;
327
splitTextureObject(renderBaseColorValue,
328
&renderBaseColorTexture,
330
&renderBaseColorObject);
332
if (!renderBaseColorValue.isEmpty() || !renderBump.isEmpty() || !renderDisplacement.isEmpty()
333
|| !renderNormal.isEmpty()) {
334
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Carpaint);
337
setAppearanceValue(finalModel, "Render.Carpaint.BaseColor", renderBaseColor);
338
setAppearanceValue(finalModel, "Render.Carpaint.BaseColor.Texture", renderBaseColorTexture);
339
setAppearanceValue(finalModel, "Render.Carpaint.BaseColor.Object", renderBaseColorObject);
340
setAppearanceValue(finalModel, "Render.Carpaint.Bump", renderBump);
341
setAppearanceValue(finalModel, "Render.Carpaint.Displacement", renderDisplacement);
342
setAppearanceValue(finalModel, "Render.Carpaint.Normal", renderNormal);
346
void MaterialConfigLoader::addRenderCycles(QMap<QString, QString>& fcmat,
347
const std::shared_ptr<Material>& finalModel)
349
QString prefix = QString::fromStdString("Render.Cycles");
350
QString string = multiLineKey(fcmat, prefix);
351
if (!string.isEmpty()) {
352
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Cycles);
355
setAppearanceValue(finalModel, "Render.Cycles", string);
359
void MaterialConfigLoader::addRenderDiffuse(QMap<QString, QString>& fcmat,
360
const std::shared_ptr<Material>& finalModel)
362
QString renderBump = value(fcmat, "Render/Render.Diffuse.Bump", "");
363
QString renderColorValue = value(fcmat, "Render/Render.Diffuse.Color", "");
364
QString renderDisplacement = value(fcmat, "Render/Render.Diffuse.Displacement", "");
365
QString renderNormal = value(fcmat, "Render/Render.Diffuse.Normal", "");
367
// Split out the textures
369
QString renderColorTexture;
370
QString renderColorObject;
371
splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject);
373
if (!renderBump.isEmpty() || !renderColorValue.isEmpty() || !renderDisplacement.isEmpty()
374
|| !renderNormal.isEmpty()) {
375
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Diffuse);
378
setAppearanceValue(finalModel, "Render.Diffuse.Bump", renderBump);
379
setAppearanceValue(finalModel, "Render.Diffuse.Color", renderColor);
380
setAppearanceValue(finalModel, "Render.Diffuse.Color.Texture", renderColorTexture);
381
setAppearanceValue(finalModel, "Render.Diffuse.Color.Object", renderColorObject);
382
setAppearanceValue(finalModel, "Render.Diffuse.Displacement", renderDisplacement);
383
setAppearanceValue(finalModel, "Render.Diffuse.Normal", renderNormal);
387
void MaterialConfigLoader::addRenderDisney(QMap<QString, QString>& fcmat,
388
const std::shared_ptr<Material>& finalModel)
390
QString renderAnisotropicValue = value(fcmat, "Render/Render.Disney.Anisotropic", "");
391
QString renderBaseColorValue = value(fcmat, "Render/Render.Disney.BaseColor", "");
392
QString renderBump = value(fcmat, "Render/Render.Disney.Bump", "");
393
QString renderClearCoatValue = value(fcmat, "Render/Render.Disney.ClearCoat", "");
394
QString renderClearCoatGlossValue = value(fcmat, "Render/Render.Disney.ClearCoatGloss", "");
395
QString renderDisplacement = value(fcmat, "Render/Render.Disney.Displacement", "");
396
QString renderMetallicValue = value(fcmat, "Render/Render.Disney.Metallic", "");
397
QString renderNormal = value(fcmat, "Render/Render.Disney.Normal", "");
398
QString renderRoughnessValue = value(fcmat, "Render/Render.Disney.Roughness", "");
399
QString renderSheenValue = value(fcmat, "Render/Render.Disney.Sheen", "");
400
QString renderSheenTintValue = value(fcmat, "Render/Render.Disney.SheenTint", "");
401
QString renderSpecularValue = value(fcmat, "Render/Render.Disney.Specular", "");
402
QString renderSpecularTintValue = value(fcmat, "Render/Render.Disney.SpecularTint", "");
403
QString renderSubsurfaceValue = value(fcmat, "Render/Render.Disney.Subsurface", "");
405
// Split out the textures
406
QString renderAnisotropic;
407
QString renderAnisotropicTexture;
408
splitTexture(renderAnisotropicValue, &renderAnisotropicTexture, &renderAnisotropic);
409
QString renderBaseColor;
410
QString renderBaseColorTexture;
411
QString renderBaseColorObject;
412
splitTextureObject(renderBaseColorValue,
413
&renderBaseColorTexture,
415
&renderBaseColorObject);
416
QString renderClearCoat;
417
QString renderClearCoatTexture;
418
QString renderClearCoatObject;
419
splitTextureObject(renderClearCoatValue,
420
&renderClearCoatTexture,
422
&renderClearCoatObject);
423
QString renderClearCoatGloss;
424
QString renderClearCoatGlossTexture;
425
QString renderClearCoatGlossObject;
426
splitTextureObject(renderClearCoatGlossValue,
427
&renderClearCoatGlossTexture,
428
&renderClearCoatGloss,
429
&renderClearCoatGlossObject);
430
QString renderMetallic;
431
QString renderMetallicTexture;
432
splitTexture(renderMetallicValue, &renderMetallicTexture, &renderMetallic);
433
QString renderRoughness;
434
QString renderRoughnessTexture;
435
splitTexture(renderRoughnessValue, &renderRoughnessTexture, &renderRoughness);
437
QString renderSheenTexture;
438
splitTexture(renderSheenValue, &renderSheenTexture, &renderSheen);
439
QString renderSheenTint;
440
QString renderSheenTintTexture;
441
splitTexture(renderSheenTintValue, &renderSheenTintTexture, &renderSheenTint);
442
QString renderSpecular;
443
QString renderSpecularTexture;
444
QString renderSpecularObject;
445
splitTextureObject(renderSpecularValue,
446
&renderSpecularTexture,
448
&renderSpecularObject);
449
QString renderSpecularTint;
450
QString renderSpecularTintTexture;
451
QString renderSpecularTintObject;
452
splitTextureObject(renderSpecularTintValue,
453
&renderSpecularTintTexture,
455
&renderSpecularTintObject);
456
QString renderSubsurface;
457
QString renderSubsurfaceTexture;
458
splitTexture(renderSubsurfaceValue, &renderSubsurfaceTexture, &renderSubsurface);
460
if (!renderAnisotropicValue.isEmpty() || !renderBaseColorValue.isEmpty()
461
|| !renderBump.isEmpty() || !renderClearCoatValue.isEmpty()
462
|| !renderClearCoatGlossValue.isEmpty() || !renderDisplacement.isEmpty()
463
|| !renderMetallicValue.isEmpty() || !renderNormal.isEmpty()
464
|| !renderRoughnessValue.isEmpty() || !renderSheenValue.isEmpty()
465
|| !renderSheenTintValue.isEmpty() || !renderSpecularValue.isEmpty()
466
|| !renderSpecularTintValue.isEmpty() || !renderSubsurfaceValue.isEmpty()) {
467
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Disney);
470
setAppearanceValue(finalModel, "Render.Disney.Anisotropic", renderAnisotropic);
471
setAppearanceValue(finalModel,
472
"Render.Disney.Anisotropic.Texture",
473
renderAnisotropicTexture);
474
setAppearanceValue(finalModel, "Render.Disney.BaseColor", renderBaseColor);
475
setAppearanceValue(finalModel, "Render.Disney.BaseColor.Texture", renderBaseColorTexture);
476
setAppearanceValue(finalModel, "Render.Disney.Bump", renderBump);
477
setAppearanceValue(finalModel, "Render.Disney.ClearCoat", renderClearCoat);
478
setAppearanceValue(finalModel, "Render.Disney.ClearCoat.Texture", renderClearCoatTexture);
479
setAppearanceValue(finalModel, "Render.Disney.ClearCoatGloss", renderClearCoatGloss);
480
setAppearanceValue(finalModel,
481
"Render.Disney.ClearCoatGloss.Texture",
482
renderClearCoatGlossTexture);
483
setAppearanceValue(finalModel, "Render.Disney.Displacement", renderDisplacement);
484
setAppearanceValue(finalModel, "Render.Disney.Metallic", renderMetallic);
485
setAppearanceValue(finalModel, "Render.Disney.Metallic.Texture", renderMetallicTexture);
486
setAppearanceValue(finalModel, "Render.Disney.Normal", renderNormal);
487
setAppearanceValue(finalModel, "Render.Disney.Roughness", renderRoughness);
488
setAppearanceValue(finalModel, "Render.Disney.Roughness.Texture", renderRoughnessTexture);
489
setAppearanceValue(finalModel, "Render.Disney.Sheen", renderSheen);
490
setAppearanceValue(finalModel, "Render.Disney.Sheen.Texture", renderSheenTexture);
491
setAppearanceValue(finalModel, "Render.Disney.SheenTint", renderSheenTint);
492
setAppearanceValue(finalModel, "Render.Disney.SheenTint.Texture", renderSheenTintTexture);
493
setAppearanceValue(finalModel, "Render.Disney.Specular", renderSpecular);
494
setAppearanceValue(finalModel, "Render.Disney.Specular.Texture", renderSpecularTexture);
495
setAppearanceValue(finalModel, "Render.Disney.SpecularTint", renderSpecularTint);
496
setAppearanceValue(finalModel,
497
"Render.Disney.SpecularTint.Texture",
498
renderSpecularTintTexture);
499
setAppearanceValue(finalModel, "Render.Disney.Subsurface", renderSubsurface);
500
setAppearanceValue(finalModel, "Render.Disney.Subsurface.Texture", renderSubsurfaceTexture);
504
void MaterialConfigLoader::addRenderEmission(QMap<QString, QString>& fcmat,
505
const std::shared_ptr<Material>& finalModel)
507
QString renderBump = value(fcmat, "Render/Render.Emission.Bump", "");
508
QString renderColorValue = value(fcmat, "Render/Render.Emission.Color", "");
509
QString renderNormal = value(fcmat, "Render/Render.Emission.Normal", "");
510
QString renderPowerValue = value(fcmat, "Render/Render.Emission.Power", "");
512
// Split out the textures
514
QString renderColorTexture;
515
QString renderColorObject;
516
splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject);
518
QString renderPowerTexture;
519
splitTexture(renderPowerValue, &renderPowerTexture, &renderPower);
521
if (!renderColorValue.isEmpty() || !renderBump.isEmpty() || !renderPowerValue.isEmpty()
522
|| !renderNormal.isEmpty()) {
523
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Emission);
526
setAppearanceValue(finalModel, "Render.Emission.Bump", renderBump);
527
setAppearanceValue(finalModel, "Render.Emission.Color", renderColor);
528
setAppearanceValue(finalModel, "Render.Emission.Color.Texture", renderColorTexture);
529
setAppearanceValue(finalModel, "Render.Emission.Color.Object", renderColorObject);
530
setAppearanceValue(finalModel, "Render.Emission.Normal", renderNormal);
531
setAppearanceValue(finalModel, "Render.Emission.Power", renderPower);
532
setAppearanceValue(finalModel, "Render.Emission.Power.Texture", renderPowerTexture);
536
void MaterialConfigLoader::addRenderGlass(QMap<QString, QString>& fcmat,
537
const std::shared_ptr<Material>& finalModel)
539
QString renderBump = value(fcmat, "Render/Render.Glass.Bump", "");
540
QString renderColorValue = value(fcmat, "Render/Render.Glass.Color", "");
541
QString renderIORValue = value(fcmat, "Render/Render.Glass.IOR", "");
542
QString renderDisplacement = value(fcmat, "Render/Render.Glass.Displacement", "");
543
QString renderNormal = value(fcmat, "Render/Render.Glass.Normal", "");
545
// Split out the textures
547
QString renderColorTexture;
548
QString renderColorObject;
549
splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject);
551
QString renderIORTexture;
552
splitTexture(renderIORValue, &renderIORTexture, &renderIOR);
554
if (!renderBump.isEmpty() || !renderColorValue.isEmpty() || !renderIORValue.isEmpty()
555
|| !renderDisplacement.isEmpty() || !renderNormal.isEmpty()) {
556
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Glass);
558
setAppearanceValue(finalModel, "Render.Glass.Bump", renderBump);
559
setAppearanceValue(finalModel, "Render.Glass.Color", renderColor);
560
setAppearanceValue(finalModel, "Render.Glass.Color.Texture", renderColorTexture);
561
setAppearanceValue(finalModel, "Render.Glass.Color.Object", renderColorObject);
562
setAppearanceValue(finalModel, "Render.Glass.IOR", renderIOR);
563
setAppearanceValue(finalModel, "Render.Glass.IOR.Texture", renderIORTexture);
564
setAppearanceValue(finalModel, "Render.Glass.Displacement", renderDisplacement);
565
setAppearanceValue(finalModel, "Render.Glass.Normal", renderNormal);
569
void MaterialConfigLoader::addRenderLuxcore(QMap<QString, QString>& fcmat,
570
const std::shared_ptr<Material>& finalModel)
572
QString prefix = QString::fromStdString("Render.Luxcore");
573
QString string = multiLineKey(fcmat, prefix);
575
if (!string.isEmpty()) {
576
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Luxcore);
579
setAppearanceValue(finalModel, "Render.Luxcore", string);
583
void MaterialConfigLoader::addRenderLuxrender(QMap<QString, QString>& fcmat,
584
const std::shared_ptr<Material>& finalModel)
586
QString prefix = QString::fromStdString("Render.Luxrender");
587
QString string = multiLineKey(fcmat, prefix);
589
if (!string.isEmpty()) {
590
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Luxrender);
593
setAppearanceValue(finalModel, "Render.Luxrender", string);
597
void MaterialConfigLoader::addRenderMixed(QMap<QString, QString>& fcmat,
598
const std::shared_ptr<Material>& finalModel)
600
QString renderBump = value(fcmat, "Render/Render.Mixed.Bump", "");
601
QString renderDiffuseColorValue = value(fcmat, "Render/Render.Mixed.Diffuse.Color", "");
602
QString renderDisplacement = value(fcmat, "Render/Render.Mixed.Displacement", "");
603
QString renderGlassColorValue = value(fcmat, "Render/Render.Mixed.Glass.Color", "");
604
QString renderGlassIORValue = value(fcmat, "Render/Render.Mixed.Glass.IOR", "");
605
QString renderNormal = value(fcmat, "Render/Render.Mixed.Normal", "");
606
QString renderTransparencyValue = value(fcmat, "Render/Render.Mixed.Transparency", "");
608
// Split out the textures
609
QString renderDiffuseColor;
610
QString renderDiffuseColorTexture;
611
QString renderDiffuseColorObject;
612
splitTextureObject(renderDiffuseColorValue,
613
&renderDiffuseColorTexture,
615
&renderDiffuseColorObject);
616
QString renderGlassColor;
617
QString renderGlassColorTexture;
618
QString renderGlassColorObject;
619
splitTextureObject(renderGlassColorValue,
620
&renderGlassColorTexture,
622
&renderGlassColorObject);
623
QString renderGlassIOR;
624
QString renderGlassIORTexture;
625
splitTexture(renderGlassIORValue, &renderGlassIORTexture, &renderGlassIOR);
626
QString renderTransparency;
627
QString renderTransparencyTexture;
628
splitTexture(renderTransparencyValue, &renderTransparencyTexture, &renderTransparency);
630
if (!renderBump.isEmpty() || !renderDiffuseColorValue.isEmpty() || !renderDisplacement.isEmpty()
631
|| !renderGlassColorValue.isEmpty() || !renderGlassIORValue.isEmpty()
632
|| !renderNormal.isEmpty() || !renderTransparencyValue.isEmpty()) {
633
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Mixed);
636
setAppearanceValue(finalModel, "Render.Mixed.Bump", renderBump);
637
setAppearanceValue(finalModel, "Render.Mixed.Diffuse.Color", renderDiffuseColor);
638
setAppearanceValue(finalModel,
639
"Render.Mixed.Diffuse.Color.Texture",
640
renderDiffuseColorTexture);
641
setAppearanceValue(finalModel,
642
"Render.Mixed.Diffuse.Color.Object",
643
renderDiffuseColorObject);
644
setAppearanceValue(finalModel, "Render.Mixed.Displacement", renderDisplacement);
645
setAppearanceValue(finalModel, "Render.Mixed.Glass.Color", renderGlassColor);
646
setAppearanceValue(finalModel, "Render.Mixed.Glass.Color.Texture", renderGlassColorTexture);
647
setAppearanceValue(finalModel, "Render.Mixed.Glass.Color.Object", renderGlassColorObject);
648
setAppearanceValue(finalModel, "Render.Mixed.Glass.IOR", renderGlassIOR);
649
setAppearanceValue(finalModel, "Render.Mixed.Glass.IOR.Texture", renderGlassIORTexture);
650
setAppearanceValue(finalModel, "Render.Mixed.Normal", renderNormal);
651
setAppearanceValue(finalModel, "Render.Mixed.Transparency", renderTransparency);
652
setAppearanceValue(finalModel,
653
"Render.Mixed.Transparency.Texture",
654
renderTransparencyTexture);
658
void MaterialConfigLoader::addRenderOspray(QMap<QString, QString>& fcmat,
659
const std::shared_ptr<Material>& finalModel)
661
QString prefix = QString::fromStdString("Render.Ospray");
662
QString string = multiLineKey(fcmat, prefix);
664
if (!string.isEmpty()) {
665
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Ospray);
668
setAppearanceValue(finalModel, "Render.Ospray", string);
672
void MaterialConfigLoader::addRenderPbrt(QMap<QString, QString>& fcmat,
673
const std::shared_ptr<Material>& finalModel)
675
QString prefix = QString::fromStdString("Render.Pbrt");
676
QString string = multiLineKey(fcmat, prefix);
678
if (!string.isEmpty()) {
679
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Pbrt);
682
setAppearanceValue(finalModel, "Render.Pbrt", string);
686
void MaterialConfigLoader::addRenderPovray(QMap<QString, QString>& fcmat,
687
const std::shared_ptr<Material>& finalModel)
689
QString prefix = QString::fromStdString("Render.Povray");
690
QString string = multiLineKey(fcmat, prefix);
692
if (!string.isEmpty()) {
693
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Povray);
696
setAppearanceValue(finalModel, "Render.Povray", string);
700
void MaterialConfigLoader::addRenderSubstancePBR(QMap<QString, QString>& fcmat,
701
const std::shared_ptr<Material>& finalModel)
703
QString renderBaseColorValue = value(fcmat, "Render/Render.Substance_PBR.BaseColor", "");
704
QString renderBump = value(fcmat, "Render/Render.Substance_PBR.Bump", "");
705
QString renderMetallicValue = value(fcmat, "Render/Render.Substance_PBR.Metallic", "");
706
QString renderNormal = value(fcmat, "Render/Render.Substance_PBR.Normal", "");
707
QString renderRoughnessValue = value(fcmat, "Render/Render.Substance_PBR.Roughness", "");
708
QString renderSpecularValue = value(fcmat, "Render/Render.Substance_PBR.Specular", "");
710
// Split out the textures
711
QString renderBaseColor;
712
QString renderBaseColorTexture;
713
QString renderBaseColorObject;
714
splitTextureObject(renderBaseColorValue,
715
&renderBaseColorTexture,
717
&renderBaseColorObject);
718
QString renderMetallic;
719
QString renderMetallicTexture;
720
splitTexture(renderMetallicValue, &renderMetallicTexture, &renderMetallic);
721
QString renderRoughness;
722
QString renderRoughnessTexture;
723
splitTexture(renderRoughnessValue, &renderRoughnessTexture, &renderRoughness);
724
QString renderSpecular;
725
QString renderSpecularTexture;
726
splitTexture(renderSpecularValue, &renderSpecularTexture, &renderSpecular);
728
if (!renderBaseColorValue.isEmpty() || !renderBump.isEmpty() || !renderMetallicValue.isEmpty()
729
|| !renderNormal.isEmpty() || !renderRoughnessValue.isEmpty()
730
|| !renderSpecularValue.isEmpty()) {
731
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_SubstancePBR);
734
setAppearanceValue(finalModel, "Render.Substance_PBR.BaseColor", renderBaseColor);
735
setAppearanceValue(finalModel,
736
"Render.Substance_PBR.BaseColor.Texture",
737
renderBaseColorTexture);
738
setAppearanceValue(finalModel,
739
"Render.Substance_PBR.BaseColor.Object",
740
renderBaseColorObject);
741
setAppearanceValue(finalModel, "Render.Substance_PBR.Bump", renderBump);
742
setAppearanceValue(finalModel, "Render.Substance_PBR.Metallic", renderMetallic);
743
setAppearanceValue(finalModel,
744
"Render.Substance_PBR.Metallic.Texture",
745
renderMetallicTexture);
746
setAppearanceValue(finalModel, "Render.Substance_PBR.Normal", renderNormal);
747
setAppearanceValue(finalModel, "Render.Substance_PBR.Roughness", renderRoughness);
748
setAppearanceValue(finalModel,
749
"Render.Substance_PBR.Roughness.Texture",
750
renderRoughnessTexture);
751
setAppearanceValue(finalModel, "Render.Substance_PBR.Specular", renderSpecular);
752
setAppearanceValue(finalModel,
753
"Render.Substance_PBR.Specular.Texture",
754
renderSpecularTexture);
758
void MaterialConfigLoader::addRenderTexture(QMap<QString, QString>& fcmat,
759
const std::shared_ptr<Material>& finalModel)
762
auto renderImage = std::make_shared<QList<QVariant>>();
764
QString renderRotation;
765
QString renderTranslationU;
766
QString renderTranslationV;
768
auto keys = fcmat.keys();
769
for (const auto& key : keys) {
770
if (key.startsWith(QString::fromStdString("Render/Render.Textures."))) {
771
QStringList list1 = key.split(QLatin1Char('.'));
772
if (renderName.isEmpty()) {
773
renderName = list1[2];
775
if (list1[3] == QString::fromStdString("Images")) {
776
renderImage->push_back(value(fcmat, key.toStdString(), ""));
778
else if (list1[3] == QString::fromStdString("Scale")) {
779
renderScale = value(fcmat, key.toStdString(), "");
781
else if (list1[3] == QString::fromStdString("Rotation")) {
782
renderRotation = value(fcmat, key.toStdString(), "");
784
else if (list1[3] == QString::fromStdString("TranslationU")) {
785
renderTranslationU = value(fcmat, key.toStdString(), "");
787
else if (list1[3] == QString::fromStdString(" TranslationV")) {
788
renderTranslationV = value(fcmat, key.toStdString(), "");
793
if (!renderName.isEmpty()) {
794
finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Texture);
797
setAppearanceValue(finalModel, "Render.Textures.Name", renderName);
798
setAppearanceValue(finalModel, "Render.Textures.Images", renderImage);
799
setAppearanceValue(finalModel, "Render.Textures.Scale", renderScale);
800
setAppearanceValue(finalModel, "Render.Textures.Rotation", renderRotation);
801
setAppearanceValue(finalModel, "Render.Textures.TranslationU", renderTranslationU);
802
setAppearanceValue(finalModel, "Render.Textures.TranslationV", renderTranslationV);
806
void MaterialConfigLoader::addRenderWB(QMap<QString, QString>& fcmat,
807
const std::shared_ptr<Material>& finalModel)
809
QString useObjectColor = value(fcmat, "General/UseObjectColor", "");
810
QString renderType = value(fcmat, "Render/Render.Type", "");
812
if (!renderType.isEmpty()) {
813
finalModel->addAppearance(ModelUUIDs::ModelUUID_RenderWB);
816
setAppearanceValue(finalModel, "UseObjectColor", useObjectColor);
817
setAppearanceValue(finalModel, "Render.Type", renderType);
820
addRenderAppleseed(fcmat, finalModel);
821
addRenderCarpaint(fcmat, finalModel);
822
addRenderCycles(fcmat, finalModel);
823
addRenderDiffuse(fcmat, finalModel);
824
addRenderDisney(fcmat, finalModel);
825
addRenderEmission(fcmat, finalModel);
826
addRenderGlass(fcmat, finalModel);
827
addRenderLuxcore(fcmat, finalModel);
828
addRenderLuxrender(fcmat, finalModel);
829
addRenderMixed(fcmat, finalModel);
830
addRenderOspray(fcmat, finalModel);
831
addRenderPbrt(fcmat, finalModel);
832
addRenderPovray(fcmat, finalModel);
833
addRenderSubstancePBR(fcmat, finalModel);
834
addRenderTexture(fcmat, finalModel);
837
void MaterialConfigLoader::addCosts(const QMap<QString, QString>& fcmat,
838
const std::shared_ptr<Material>& finalModel)
840
QString productURL = value(fcmat, "Cost/ProductURL", "");
841
QString specificPrice = value(fcmat, "Cost/SpecificPrice", "");
842
QString vendor = value(fcmat, "Cost/Vendor", "");
844
if (productURL.length() + specificPrice.length() + vendor.length() > 0) {
845
finalModel->addPhysical(ModelUUIDs::ModelUUID_Costs_Default);
848
setPhysicalValue(finalModel, "ProductURL", productURL);
849
setPhysicalValue(finalModel, "SpecificPrice", specificPrice);
850
setPhysicalValue(finalModel, "Vendor", vendor);
854
void MaterialConfigLoader::addArchitectural(const QMap<QString, QString>& fcmat,
855
const std::shared_ptr<Material>& finalModel)
857
QString color = value(fcmat, "Architectural/Color", "");
858
QString environmentalEfficiencyClass =
859
value(fcmat, "Architectural/EnvironmentalEfficiencyClass", "");
860
QString executionInstructions = value(fcmat, "Architectural/ExecutionInstructions", "");
861
QString finish = value(fcmat, "Architectural/Finish", "");
862
QString fireResistanceClass = value(fcmat, "Architectural/FireResistanceClass", "");
863
QString model = value(fcmat, "Architectural/Model", "");
864
QString soundTransmissionClass = value(fcmat, "Architectural/SoundTransmissionClass", "");
865
QString unitsPerQuantity = value(fcmat, "Architectural/UnitsPerQuantity", "");
867
if (environmentalEfficiencyClass.length() + executionInstructions.length()
868
+ fireResistanceClass.length() + model.length() + soundTransmissionClass.length()
869
+ unitsPerQuantity.length()
871
finalModel->addPhysical(ModelUUIDs::ModelUUID_Architectural_Default);
873
if (color.length() + finish.length() > 0) {
874
finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Architectural);
878
setPhysicalValue(finalModel, "EnvironmentalEfficiencyClass", environmentalEfficiencyClass);
879
setPhysicalValue(finalModel, "ExecutionInstructions", executionInstructions);
880
setPhysicalValue(finalModel, "FireResistanceClass", fireResistanceClass);
881
setPhysicalValue(finalModel, "Model", model);
882
setPhysicalValue(finalModel, "SoundTransmissionClass", soundTransmissionClass);
883
setPhysicalValue(finalModel, "UnitsPerQuantity", unitsPerQuantity);
885
setAppearanceValue(finalModel, "Color", color);
886
setAppearanceValue(finalModel, "Finish", finish);
889
void MaterialConfigLoader::addElectromagnetic(const QMap<QString, QString>& fcmat,
890
const std::shared_ptr<Material>& finalModel)
892
QString relativePermittivity = value(fcmat, "Electromagnetic/RelativePermittivity", "");
893
QString electricalConductivity = value(fcmat, "Electromagnetic/ElectricalConductivity", "");
894
QString relativePermeability = value(fcmat, "Electromagnetic/RelativePermeability", "");
896
if (relativePermittivity.length() + electricalConductivity.length()
897
+ relativePermeability.length()
899
finalModel->addPhysical(ModelUUIDs::ModelUUID_Electromagnetic_Default);
902
setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity);
903
setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity);
904
setPhysicalValue(finalModel, "RelativePermeability", relativePermeability);
908
void MaterialConfigLoader::addThermal(const QMap<QString, QString>& fcmat,
909
const std::shared_ptr<Material>& finalModel)
911
QString specificHeat = value(fcmat, "Thermal/SpecificHeat", "");
912
QString thermalConductivity = value(fcmat, "Thermal/ThermalConductivity", "");
913
QString thermalExpansionCoefficient = value(fcmat, "Thermal/ThermalExpansionCoefficient", "");
915
if (specificHeat.length() + thermalConductivity.length() + thermalExpansionCoefficient.length()
917
finalModel->addPhysical(ModelUUIDs::ModelUUID_Thermal_Default);
920
setPhysicalValue(finalModel, "SpecificHeat", specificHeat);
921
setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity);
922
setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient);
926
void MaterialConfigLoader::addFluid(const QMap<QString, QString>& fcmat,
927
const std::shared_ptr<Material>& finalModel)
929
QString density = value(fcmat, "Fluidic/Density", "");
930
QString dynamicViscosity = value(fcmat, "Fluidic/DynamicViscosity", "");
931
QString kinematicViscosity = value(fcmat, "Fluidic/KinematicViscosity", "");
932
QString prandtlNumber = value(fcmat, "Fluidic/PrandtlNumber", "");
934
// Check which model we need
935
bool useDensity = false;
936
bool useFluid = false;
937
if (density.length() > 0) {
940
if (dynamicViscosity.length() + kinematicViscosity.length() + prandtlNumber.length() > 0) {
945
finalModel->addPhysical(ModelUUIDs::ModelUUID_Fluid_Default);
947
else if (useDensity) {
948
finalModel->addPhysical(ModelUUIDs::ModelUUID_Mechanical_Density);
952
setPhysicalValue(finalModel, "Density", density);
953
setPhysicalValue(finalModel, "DynamicViscosity", dynamicViscosity);
954
setPhysicalValue(finalModel, "KinematicViscosity", kinematicViscosity);
955
setPhysicalValue(finalModel, "PrandtlNumber", prandtlNumber);
958
void MaterialConfigLoader::addMechanical(const QMap<QString, QString>& fcmat,
959
const std::shared_ptr<Material>& finalModel)
961
QString density = value(fcmat, "Mechanical/Density", "");
962
QString bulkModulus = value(fcmat, "Mechanical/BulkModulus", "");
963
QString poissonRatio = value(fcmat, "Mechanical/PoissonRatio", "");
964
QString shearModulus = value(fcmat, "Mechanical/ShearModulus", "");
965
QString youngsModulus = value(fcmat, "Mechanical/YoungsModulus", "");
966
QString angleOfFriction = value(fcmat, "Mechanical/AngleOfFriction", "");
967
QString compressiveStrength = value(fcmat, "Mechanical/CompressiveStrength", "");
968
QString fractureToughness = value(fcmat, "Mechanical/FractureToughness", "");
969
QString ultimateStrain = value(fcmat, "Mechanical/UltimateStrain", "");
970
QString ultimateTensileStrength = value(fcmat, "Mechanical/UltimateTensileStrength", "");
971
QString yieldStrength = value(fcmat, "Mechanical/YieldStrength", "");
972
QString stiffness = value(fcmat, "Mechanical/Stiffness", "");
974
// Check which model we need
975
bool useDensity = false;
977
bool useLinearElastic = false;
978
if (density.length() > 0) {
981
if (bulkModulus.length() + poissonRatio.length() + shearModulus.length()
982
+ youngsModulus.length()
986
if (angleOfFriction.length() + compressiveStrength.length() + fractureToughness.length()
987
+ ultimateStrain.length() + ultimateTensileStrength.length() + yieldStrength.length()
990
useLinearElastic = true;
993
if (useLinearElastic) {
994
finalModel->addPhysical(ModelUUIDs::ModelUUID_Mechanical_LinearElastic);
998
finalModel->addPhysical(ModelUUIDs::ModelUUID_Mechanical_IsotropicLinearElastic);
1001
finalModel->addPhysical(ModelUUIDs::ModelUUID_Mechanical_Density);
1006
setPhysicalValue(finalModel, "Density", density);
1007
setPhysicalValue(finalModel, "BulkModulus", bulkModulus);
1008
setPhysicalValue(finalModel, "PoissonRatio", poissonRatio);
1009
setPhysicalValue(finalModel, "ShearModulus", shearModulus);
1010
setPhysicalValue(finalModel, "YoungsModulus", youngsModulus);
1011
setPhysicalValue(finalModel, "AngleOfFriction", angleOfFriction);
1012
setPhysicalValue(finalModel, "CompressiveStrength", compressiveStrength);
1013
setPhysicalValue(finalModel, "FractureToughness", fractureToughness);
1014
setPhysicalValue(finalModel, "UltimateStrain", ultimateStrain);
1015
setPhysicalValue(finalModel, "UltimateTensileStrength", ultimateTensileStrength);
1016
setPhysicalValue(finalModel, "YieldStrength", yieldStrength);
1017
setPhysicalValue(finalModel, "Stiffness", stiffness);
1020
void MaterialConfigLoader::addLegacy(const QMap<QString, QString>& fcmat,
1021
const std::shared_ptr<Material>& finalModel)
1023
for (auto const& legacy : fcmat.keys()) {
1025
int last = name.lastIndexOf(QLatin1String("/"));
1027
name = name.mid(last + 1);
1030
if (!finalModel->hasNonLegacyProperty(name)) {
1031
setLegacyValue(finalModel, name.toStdString(), fcmat[legacy]);
1036
std::shared_ptr<Material>
1037
MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library,
1038
const QString& path)
1040
QString author = getAuthorAndLicense(path); // Place them both in the author field
1042
QMap<QString, QString> fcmat;
1043
if (!readFile(path, fcmat)) {
1044
Base::Console().Log("Error reading '%s'\n", path.toStdString().c_str());
1045
throw MaterialReadError();
1049
// QString name = value(fcmat, "Name", ""); - always get the name from the filename
1050
QFileInfo filepath(path);
1052
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
1053
QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
1055
QString description = value(fcmat, "Description", "");
1056
QString sourceReference = value(fcmat, "ReferenceSource", "");
1057
QString sourceURL = value(fcmat, "SourceURL", "");
1059
std::shared_ptr<Material> finalModel = std::make_shared<Material>(library, path, uuid, name);
1060
finalModel->setOldFormat(true);
1062
finalModel->setAuthor(author);
1063
finalModel->setDescription(description);
1064
finalModel->setReference(sourceReference);
1065
finalModel->setURL(sourceURL);
1067
QString father = value(fcmat, "Father", "");
1068
if (!father.isEmpty()) {
1069
finalModel->addPhysical(ModelUUIDs::ModelUUID_Legacy_Father);
1072
setPhysicalValue(finalModel, "Father", father);
1075
QString kindOfMaterial = value(fcmat, "KindOfMaterial", "");
1076
QString materialNumber = value(fcmat, "MaterialNumber", "");
1077
QString norm = value(fcmat, "Norm", "");
1078
QString standardCode = value(fcmat, "StandardCode", "");
1079
if (kindOfMaterial.length() + materialNumber.length() + norm.length() + standardCode.length()
1081
finalModel->addPhysical(ModelUUIDs::ModelUUID_Legacy_MaterialStandard);
1084
setPhysicalValue(finalModel, "KindOfMaterial", kindOfMaterial);
1085
setPhysicalValue(finalModel, "MaterialNumber", materialNumber);
1086
setPhysicalValue(finalModel, "StandardCode", norm); // Norm is the same as StandardCode
1087
setPhysicalValue(finalModel, "StandardCode", standardCode);
1090
// Add the remaining sections
1091
addMechanical(fcmat, finalModel);
1092
addFluid(fcmat, finalModel);
1093
addThermal(fcmat, finalModel);
1094
addElectromagnetic(fcmat, finalModel);
1095
addArchitectural(fcmat, finalModel);
1096
addCosts(fcmat, finalModel);
1097
addRendering(fcmat, finalModel);
1098
addVectorRendering(fcmat, finalModel);
1099
addRenderWB(fcmat, finalModel);
1100
addLegacy(fcmat, finalModel);