import {
Material,
LineBasicMaterial,
LineDashedMaterial,
MeshBasicMaterial,
MeshDepthMaterial,
MeshDistanceMaterial,
MeshLambertMaterial,
MeshMatcapMaterial,
MeshNormalMaterial,
MeshPhongMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
MeshToonMaterial,
PointsMaterial,
RawShaderMaterial,
ShaderMaterial,
ShadowMaterial,
SpriteMaterial,
DoubleSide
} from '../../../node_modules/three/build/three.module.js';
//NodeMaterials
import { NodeMaterialLoader, NodeMaterialLoaderUtils } from '../../../node_modules/three/examples/jsm/loaders/NodeMaterialLoader.js';
import * as Nodes from '../../../node_modules/three/examples/jsm/nodes/Nodes.js';
import { buildNodeMaterial } from '../../utilities/nodeMaterialBuilder.js';
import { Reporter } from '../../reporter/reporter.js';
import { Package } from '../../package/package.js';
import { WrappedTexture } from '../wrapped_texture.js';
import { BuildableComponent } from '../component/buildable_component.js';
import { WrappedImage } from '../image/wrapped_image.js';
import { checkPropTypes, copyProps, omit, UUIDRegex } from '../../lib.js';
import { MaterialCategory } from './material_category.js';
import { EnvironmentMap } from '../environment_map.js';
import { Project } from '../../project.js';
import { MaterialSet } from '../material/material_set.js';
/** ProductBuilder Material */
class WrappedMaterial extends BuildableComponent {
// typescript understands this, but jsdoc crashes
// /**
// * @param {Reporter} reporter
// * @param {{[k: string]: any, id?: UUID, type: MaterialType, thumbnail?: WrappedImage } } settings
// */
/**
* @param {Reporter} reporter
* @param {Object} settings
* @param {UUID} [settings.id]
* @param {string} [settings.name]
* @param {MaterialType} settings.type
* @param {Array<MaterialCategory>} [settings.categories]
* @param {WrappedImage} [settings.thumbnail]
* @param {WrappedTexture} [settings.alphaMap]
* @param {WrappedTexture} [settings.aoMap]
* @param {EnvironmentMap} [settings.envMap]
* @param {WrappedTexture} [settings.lightMap]
* @param {WrappedTexture} [settings.map]
* @param {WrappedTexture} [settings.specularMap]
* @param {WrappedTexture} [settings.displacementMap]
* @param {WrappedTexture} [settings.emissiveMap]
* @param {WrappedTexture} [settings.bumpMap]
* @param {WrappedTexture} [settings.normalMap]
* @param {WrappedTexture} [settings.clearcoatMap]
* @param {WrappedTexture} [settings.clearcoatNormalMap]
* @param {WrappedTexture} [settings.gradientMap]
* @param {WrappedTexture} [settings.parallaxMap]
* @param {any} [settings.color]
// * @param {any} [settings.x: string]
*/
constructor(reporter, settings, instructions = {}) {
if (instructions.tree && instructions.tree.environmentMaps) {
if (!settings.envMap) {
settings.envMap = instructions.tree.environmentMaps[0];
}
}
super(
reporter,
settings,
{
parse: {
categories: 'integral'
}
}
);
// would be nice to check against "instanceof Material"
// but THREE classes' prototypes point to themselves
// for some reason
checkPropTypes(
settings,
{
type: val => WrappedMaterial.materialTypes[val] !== undefined
},
{
alphaMap: WrappedTexture,
aoMap: WrappedTexture,
envMap: EnvironmentMap,
lightMap: WrappedTexture,
map: WrappedTexture,
specularMap: WrappedTexture,
displacementMap: WrappedTexture,
emissiveMap: WrappedTexture,
bumpMap: WrappedTexture,
normalMap: WrappedTexture,
clearcoatMap: WrappedTexture,
clearcoatNormalMap: WrappedTexture,
gradientMap: WrappedTexture,
parallaxMap: WrappedTexture,
}
);
// this.exportName = 'materials';
// material presentability depends only on the thumb's usability
if (this.settings.thumbnail) {
this.settings.thumbnail.on('usability-changed', thumbUsability => {
this._UIStatus = thumbUsability;
});
}
}
static _exportName = {
singular: 'material',
plural: 'materials'
};
/** @type {Object<string,Object>} */
static materialTypes = {
Nodes,
LineBasicMaterial,
LineDashedMaterial,
Material,
MeshBasicMaterial,
MeshDepthMaterial,
MeshDistanceMaterial,
MeshLambertMaterial,
MeshMatcapMaterial,
MeshNormalMaterial,
MeshPhongMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
MeshToonMaterial,
PointsMaterial,
RawShaderMaterial,
ShaderMaterial,
ShadowMaterial,
SpriteMaterial
};
/** @returns {Array<MaterialSet>} */
getMaterialSets() {
if ( ! this._tree ) {
return [];
}
else {
return (this._tree.materialSets || []).filter( set => set.has( this ));
}
}
get materialSets() {
return this.getMaterialSets()
}
/**
* Build material
* @param {ComponentPart} part
* @param {LoadingQuality} quality
* @returns {Promise<WrappedMaterial>}
*/
async _build(part, quality) {
switch (part) {
case 'UI':
if (this._settings.thumbnail) {
this._setContent('UI', quality, this._settings.thumbnail.content.main[quality]);
}
else {
this._setContent('UI', quality, Project.defaultImages.missing.cloneNode(true));
}
break;
case 'main':
if( this._settings.type === 'Nodes'){
console.log( "node material 123")
// //get the product normal texture
// const normalTexture = this.moobel.assets.textures[ `tex__prod_norm__${blockInstance.instanceOf}` ]
// //create texture node with the product normal map
// const normalNode = normalTexture
// ? new Nodes.TextureNode( this.moobel.assets.textures[ `tex__prod_norm__${blockInstance.instanceOf}` ] )
// : undefined
// // console.log( normalTexture, normalNode )
// //create the node material
// const nodeMaterial = buildNodeMaterial(
// material, //material to apply the product map to
// this.moobel.assets.textures, //texture -> can be removed
// normalNode,
// { x: clone.userData.normalMap.tiling[ 0 ], y: clone.userData.normalMap.tiling[ 1 ] } //welke tiling is dit?
// )
// // console.log( nodeMaterial )
//this._setContent('main', quality, nodeMaterial);
}
else
{
const material = new WrappedMaterial.materialTypes[this._settings.type]();
material.userData = {
PB: {
origin: this.id
}
}
const textureSettings = Object.keys(this._settings).filter(key => this._settings[key] instanceof WrappedTexture);
//console.log( textureSettings )
let propsToCopy = Object.keys(material).filter(prop => !textureSettings.includes(prop));
//console.log( this.settings )
const settingSources = [ this._settings, ...(this._settings.categories || []) ];
for ( let settingSource of settingSources ) {
const copiedProps = copyProps({
from: settingSource,
into: material,
required: [],
optional: propsToCopy
});
propsToCopy = propsToCopy.filter( entry => ! copiedProps.includes(entry));
for (let textureSetting of textureSettings) {
if(settingSource[textureSetting] && ! material[textureSetting]) {
material[textureSetting] = settingSource[textureSetting].content.main[quality];
}
}
}
// If this material was loaded as part of a package (not as standalone object)
// and an environment map is defined in the package, this material will have added
// it to its settings and depencies in the constructor. If, however, the material
// was added to a package later, it will not have the envMap as dependency
// therefore, check again here if one is available now
if (!textureSettings.environmentMap && this._tree && this._tree.environmentMaps && this._tree.environmentMaps[ 0 ] instanceof EnvironmentMap) {
const envMap = this._tree.environmentMaps[0];
if (envMap.status.main[quality] !== 'ready') {
console.warn(`Can not apply ${envMap.label} to ${this.label}, status should be "ready" but is "${envMap.status.main[quality]}".`);
}
else {
material.envMap = this._tree.environmentMaps[0].content.main[quality];
}
}
//material.side = DoubleSide
material.needsUpdate = true;
//console.log( material )
this._setContent('main', quality, material);
}
break;
default:
this._setContent(part, quality, null);
break;
}
return this;
}
}
export { WrappedMaterial };