UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

580 lines (579 loc) 18.8 kB
"use strict"; import { TypedCopNode } from "../_Base"; import { RGBAFormat, UnsignedByteType, NoColorSpace, UVMapping, RepeatWrapping, LinearFilter } from "three"; import { MAG_FILTERS, MAG_FILTER_DEFAULT_VALUE, MAG_FILTER_MENU_ENTRIES, MIN_FILTERS, MIN_FILTER_DEFAULT_VALUE, MIN_FILTER_MENU_ENTRIES } from "../../../../core/cop/Filter"; import { NodeParamsConfig, ParamConfig } from "../../utils/params/ParamsConfig"; import { CopRendererController } from "./RendererController"; import { isBooleanTrue } from "../../../../core/BooleanValue"; import { COLOR_SPACES, COLOR_SPACE_NAME_BY_COLOR_SPACE } from "../../../../core/cop/ColorSpace"; import { WRAPPINGS } from "../../../../core/cop/Wrapping"; import { MAPPINGS } from "../../../../core/cop/Mapping"; import { TEXTURE_TYPES } from "../../../../core/cop/Type"; import { TEXTURE_FORMATS } from "../../../../core/cop/Format"; function callbackParams(method) { return { cook: false, callback: (node) => { TextureParamsController[method](node); } }; } const DEFAULT = { COLOR_SPACE: NoColorSpace, FORMAT: RGBAFormat, MAPPING: UVMapping, MIN_FILTER: LinearFilter, MAG_FILTER: LinearFilter, TYPE: UnsignedByteType, WRAPPING: RepeatWrapping }; const CALLBACK_PARAMS_ENCODING = callbackParams("PARAM_CALLBACK_update_encoding"); const CALLBACK_PARAMS_MAPPING = callbackParams("PARAM_CALLBACK_update_mapping"); const CALLBACK_PARAMS_WRAP = callbackParams("PARAM_CALLBACK_update_wrap"); const CALLBACK_PARAMS_FILTER = callbackParams("PARAM_CALLBACK_update_filter"); const CALLBACK_PARAMS_ANISOTROPY = callbackParams("PARAM_CALLBACK_update_anisotropy"); const CALLBACK_PARAMS_FLIPY = callbackParams("PARAM_CALLBACK_update_flipY"); const CALLBACK_PARAMS_TRANSFORM_TRANSFORM = callbackParams("PARAM_CALLBACK_update_transform"); const CALLBACK_PARAMS_TRANSFORM_REPEAT = callbackParams("PARAM_CALLBACK_update_repeat"); const CALLBACK_PARAMS_TRANSFORM_OFFSET = callbackParams("PARAM_CALLBACK_update_offset"); const CALLBACK_PARAMS_TRANSFORM_ROTATION = callbackParams("PARAM_CALLBACK_update_rotation"); const CALLBACK_PARAMS_TRANSFORM_CENTER = callbackParams("PARAM_CALLBACK_update_center"); const CALLBACK_PARAMS_ADVANCED = callbackParams("PARAM_CALLBACK_update_advanced"); export function TextureParamConfig(Base, defaults) { return class Mixin extends Base { constructor() { super(...arguments); /** @param toggle on to allow updating the texture encoding */ this.tcolorSpace = ParamConfig.BOOLEAN((defaults == null ? void 0 : defaults.tcolorSpace) || 0, { ...CALLBACK_PARAMS_ENCODING }); /** @param sets the texture encoding */ this.colorSpace = ParamConfig.STRING((defaults == null ? void 0 : defaults.colorSpace) || DEFAULT.COLOR_SPACE, { visibleIf: { tcolorSpace: 1 }, menuString: { entries: COLOR_SPACES.map((colorSpace) => ({ name: COLOR_SPACE_NAME_BY_COLOR_SPACE[colorSpace], value: colorSpace })) }, ...CALLBACK_PARAMS_ENCODING }); /** @param toggle on to allow updating the texture mapping */ this.tmapping = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_MAPPING }); /** @param sets the texture mapping */ this.mapping = ParamConfig.INTEGER(DEFAULT.MAPPING, { visibleIf: { tmapping: 1 }, menu: { entries: MAPPINGS.map((m) => { return { name: Object.keys(m)[0], value: Object.values(m)[0] }; }) }, ...CALLBACK_PARAMS_MAPPING }); /** @param toggle on to allow updating the texture wrap */ this.twrap = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_WRAP }); /** @param sets the texture wrapS */ this.wrapS = ParamConfig.INTEGER(DEFAULT.WRAPPING, { visibleIf: { twrap: 1 }, menu: { entries: WRAPPINGS.map((m) => { return { name: Object.keys(m)[0], value: Object.values(m)[0] }; }) }, ...CALLBACK_PARAMS_WRAP }); /** @param sets the texture wrapT */ this.wrapT = ParamConfig.INTEGER(DEFAULT.WRAPPING, { visibleIf: { twrap: 1 }, menu: { entries: WRAPPINGS.map((m) => { return { name: Object.keys(m)[0], value: Object.values(m)[0] }; }) }, separatorAfter: true, ...CALLBACK_PARAMS_WRAP }); /** @param toggle on to allow updating the texture min filter */ this.tminFilter = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_FILTER }); /** @param sets the texture min filter */ this.minFilter = ParamConfig.INTEGER(MIN_FILTER_DEFAULT_VALUE, { visibleIf: { tminFilter: 1 }, menu: { entries: MIN_FILTER_MENU_ENTRIES }, ...CALLBACK_PARAMS_FILTER }); /** @param toggle on to allow updating the texture mag filter */ this.tmagFilter = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_FILTER }); /** @param sets the texture mag filter */ this.magFilter = ParamConfig.INTEGER(MAG_FILTER_DEFAULT_VALUE, { visibleIf: { tmagFilter: 1 }, menu: { entries: MAG_FILTER_MENU_ENTRIES }, ...CALLBACK_PARAMS_FILTER }); /** @param toggle on to allow updating the texture anisotropy */ this.tanisotropy = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_ANISOTROPY }); /** @param sets the anisotropy from the max value allowed by the renderer */ this.useRendererMaxAnisotropy = ParamConfig.BOOLEAN(0, { visibleIf: { tanisotropy: 1 }, ...CALLBACK_PARAMS_ANISOTROPY }); /** @param sets the anisotropy manually */ this.anisotropy = ParamConfig.INTEGER(2, { visibleIf: { tanisotropy: 1, useRendererMaxAnisotropy: 0 }, range: [0, 32], rangeLocked: [true, false], ...CALLBACK_PARAMS_ANISOTROPY }); /** @param Toggle on to update the flipY */ this.tflipY = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_FLIPY }); /** @param sets the flipY */ this.flipY = ParamConfig.BOOLEAN(0, { visibleIf: { tflipY: 1 }, ...CALLBACK_PARAMS_FLIPY }); /** @param toggle on to update the texture transform */ this.ttransform = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_TRANSFORM_TRANSFORM }); /** @param updates the texture offset */ this.offset = ParamConfig.VECTOR2([0, 0], { visibleIf: { ttransform: 1 }, ...CALLBACK_PARAMS_TRANSFORM_OFFSET }); /** @param updates the texture repeat */ this.repeat = ParamConfig.VECTOR2([1, 1], { visibleIf: { ttransform: 1 }, ...CALLBACK_PARAMS_TRANSFORM_REPEAT }); /** @param updates the texture rotation */ this.rotation = ParamConfig.FLOAT(0, { range: [-1, 1], visibleIf: { ttransform: 1 }, ...CALLBACK_PARAMS_TRANSFORM_ROTATION }); /** @param updates the texture center */ this.center = ParamConfig.VECTOR2([0, 0], { visibleIf: { ttransform: 1 }, ...CALLBACK_PARAMS_TRANSFORM_CENTER }); /** @param toggle on to display advanced parameters */ this.tadvanced = ParamConfig.BOOLEAN(0, { ...CALLBACK_PARAMS_ADVANCED, separatorBefore: true }); /** @param toggle on to allow overriding the texture format */ this.tformat = ParamConfig.BOOLEAN(0, { visibleIf: { tadvanced: 1 }, ...CALLBACK_PARAMS_ADVANCED }); /** @param sets the texture format */ this.format = ParamConfig.INTEGER(DEFAULT.FORMAT, { visibleIf: { tadvanced: 1, tformat: 1 }, menu: { entries: TEXTURE_FORMATS.map((m) => { return { name: Object.keys(m)[0], value: Object.values(m)[0] }; }) }, ...CALLBACK_PARAMS_ADVANCED }); /** @param toggle on to allow overriding the texture type */ this.ttype = ParamConfig.BOOLEAN(0, { visibleIf: { tadvanced: 1 }, ...CALLBACK_PARAMS_ADVANCED }); /** @param sets the texture ty[e] */ this.type = ParamConfig.INTEGER(DEFAULT.TYPE, { visibleIf: { tadvanced: 1, ttype: 1 }, menu: { entries: TEXTURE_TYPES.map((m) => { return { name: Object.keys(m)[0], value: Object.values(m)[0] }; }) }, ...CALLBACK_PARAMS_ADVANCED }); } }; } class CopTextureParamsConfig extends TextureParamConfig(NodeParamsConfig) { } const ParamsConfig = new CopTextureParamsConfig(); class TextureCopNode extends TypedCopNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this.textureParamsController = new TextureParamsController(this); } } export class TextureParamsController { constructor(node) { this.node = node; } async update(texture) { const pv = this.node.pv; this._updateColorSpace(texture, pv); this._updateAdvanced(texture, pv); this._updateMapping(texture, pv); this._updateWrap(texture, pv); this._updateFilter(texture, pv); this._updateFlip(texture, pv); await this._updateAnisotropy(texture, pv); this._updateTransform(texture); } _updateColorSpace(texture, pv) { if (isBooleanTrue(pv.tcolorSpace)) { texture.colorSpace = pv.colorSpace; } else { texture.colorSpace = DEFAULT.COLOR_SPACE; } texture.needsUpdate = true; } _updateAdvanced(texture, pv) { if (isBooleanTrue(pv.tadvanced)) { if (isBooleanTrue(pv.tformat)) { texture.format = pv.format; } else { texture.format = DEFAULT.FORMAT; } if (isBooleanTrue(pv.ttype)) { texture.type = pv.type; } else { texture.type = DEFAULT.TYPE; } } texture.needsUpdate = true; } _updateMapping(texture, pv) { if (isBooleanTrue(pv.tmapping)) { texture.mapping = pv.mapping; } else { texture.mapping = DEFAULT.MAPPING; } texture.needsUpdate = true; } _updateWrap(texture, pv) { if (isBooleanTrue(pv.twrap)) { texture.wrapS = pv.wrapS; texture.wrapT = pv.wrapT; } else { texture.wrapS = DEFAULT.WRAPPING; texture.wrapT = DEFAULT.WRAPPING; } texture.needsUpdate = true; } _updateFilter(texture, pv) { if (isBooleanTrue(pv.tminFilter)) { texture.minFilter = pv.minFilter; } else { texture.minFilter = LinearFilter; } if (isBooleanTrue(pv.tmagFilter)) { texture.magFilter = pv.magFilter; } else { texture.magFilter = LinearFilter; } texture.needsUpdate = true; } _updateFlip(texture, pv) { texture.flipY = pv.tflipY && pv.flipY; texture.needsUpdate = true; } async _updateAnisotropy(texture, pv) { if (!isBooleanTrue(pv.tanisotropy)) { texture.anisotropy = 1; return; } if (isBooleanTrue(pv.useRendererMaxAnisotropy)) { texture.anisotropy = await this._maxRendererAnisotropy(); } else { const anisotropy = pv.anisotropy; if (anisotropy <= 2) { texture.anisotropy = anisotropy; } else { texture.anisotropy = Math.min(anisotropy, await this._maxRendererAnisotropy()); } } texture.needsUpdate = true; } async _maxRendererAnisotropy() { this._rendererController = this._rendererController || new CopRendererController(this.node); const renderer = await this._rendererController.waitForRenderer(); if (!renderer) { return 1; } const maxAnisotropy = renderer.capabilities.getMaxAnisotropy(); return maxAnisotropy; } _updateTransform(texture) { if (!isBooleanTrue(this.node.pv.ttransform)) { texture.offset.set(0, 0); texture.rotation = 0; texture.repeat.set(1, 1); texture.center.set(0, 0); return; } this._updateTransformOffset(texture, false); this._updateTransformRepeat(texture, false); this._updateTransformRotation(texture, false); this._updateTransformCenter(texture, false); texture.updateMatrix(); } async _updateTransformOffset(texture, updateMatrix) { texture.offset.copy(this.node.pv.offset); if (updateMatrix) { texture.updateMatrix(); } } async _updateTransformRepeat(texture, updateMatrix) { texture.repeat.copy(this.node.pv.repeat); if (updateMatrix) { texture.updateMatrix(); } } async _updateTransformRotation(texture, updateMatrix) { texture.rotation = this.node.pv.rotation; if (updateMatrix) { texture.updateMatrix(); } } async _updateTransformCenter(texture, updateMatrix) { texture.center.copy(this.node.pv.center); if (updateMatrix) { texture.updateMatrix(); } } // // // CALLBACK // // static PARAM_CALLBACK_update_encoding(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateColorSpace(texture, node.pv); } static PARAM_CALLBACK_update_mapping(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateMapping(texture, node.pv); } static PARAM_CALLBACK_update_wrap(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateWrap(texture, node.pv); } static PARAM_CALLBACK_update_filter(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateFilter(texture, node.pv); } static PARAM_CALLBACK_update_anisotropy(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateAnisotropy(texture, node.pv); } static PARAM_CALLBACK_update_flipY(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateFlip(texture, node.pv); } static PARAM_CALLBACK_update_transform(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateTransform(texture); } static PARAM_CALLBACK_update_offset(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateTransformOffset(texture, true); } static PARAM_CALLBACK_update_repeat(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateTransformRepeat(texture, true); } static PARAM_CALLBACK_update_rotation(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateTransformRotation(texture, true); } static PARAM_CALLBACK_update_center(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateTransformCenter(texture, true); } static PARAM_CALLBACK_update_advanced(node) { const texture = node.containerController.container().texture(); if (!texture) { return; } node.textureParamsController._updateAdvanced(texture, node.pv); } // // // UTILS // // static copyTextureAttributes(texture, inputTexture) { texture.colorSpace = inputTexture.colorSpace; texture.mapping = inputTexture.mapping; texture.wrapS = inputTexture.wrapS; texture.wrapT = inputTexture.wrapT; texture.minFilter = inputTexture.minFilter; texture.magFilter = inputTexture.magFilter; texture.magFilter = inputTexture.magFilter; texture.anisotropy = inputTexture.anisotropy; texture.flipY = inputTexture.flipY; texture.repeat.copy(inputTexture.repeat); texture.offset.copy(inputTexture.offset); texture.center.copy(inputTexture.center); texture.rotation = inputTexture.rotation; texture.type = inputTexture.type; texture.format = inputTexture.format; texture.needsUpdate = true; } paramLabelsParams() { const p = this.node.p; return [ // colorSpace p.tcolorSpace, p.colorSpace, // mapping p.tmapping, p.mapping, // wrap p.twrap, p.wrapS, p.wrapT, // filter p.tminFilter, p.minFilter, p.tmagFilter, p.magFilter, // flipY p.tflipY, p.flipY ]; } paramLabels() { const labels = []; const pv = this.node.pv; if (isBooleanTrue(pv.tcolorSpace)) { for (const colorSpace of COLOR_SPACES) { if (colorSpace == pv.colorSpace) { labels.push(`colorSpace: ${colorSpace}`); } } } if (isBooleanTrue(pv.tmapping)) { for (const mapping of MAPPINGS) { const mappingName = Object.keys(mapping)[0]; const mappingValue = mapping[mappingName]; if (mappingValue == pv.mapping) { labels.push(`mapping: ${mappingName}`); } } } if (isBooleanTrue(pv.twrap)) { let setWrapping2 = function(wrappingAxis) { for (const wrapping of WRAPPINGS) { const wrappingName = Object.keys(wrapping)[0]; const wrappingValue = wrapping[wrappingName]; if (wrappingValue == pv[wrappingAxis]) { labels.push(`${wrappingAxis}: ${wrappingName}`); } } }; var setWrapping = setWrapping2; setWrapping2("wrapS"); setWrapping2("wrapT"); } if (isBooleanTrue(pv.tminFilter)) { for (const minFilter of MIN_FILTERS) { const minFilterName = Object.keys(minFilter)[0]; const minFilterValue = minFilter[minFilterName]; if (minFilterValue == pv.minFilter) { labels.push(`minFilter: ${minFilterName}`); } } } if (isBooleanTrue(pv.tmagFilter)) { for (const magFilter of MAG_FILTERS) { const magFilterName = Object.keys(magFilter)[0]; const magFilterValue = magFilter[magFilterName]; if (magFilterValue == pv.magFilter) { labels.push(`magFilter: ${magFilterName}`); } } } if (isBooleanTrue(pv.tflipY)) { labels.push(`flipY: ${pv.flipY}`); } return labels; } }