@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
580 lines (579 loc) • 18.8 kB
JavaScript
"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;
}
}