@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
291 lines (290 loc) • 10.1 kB
JavaScript
"use strict";
import { TypedSopNode } from "./_Base";
import {
AttribClassMenuEntries,
AttribTypeMenuEntries,
AttribClass,
AttribType,
ATTRIBUTE_CLASSES,
ATTRIBUTE_TYPES
} from "../../../core/geometry/Constant";
import { CoreAttribute } from "../../../core/geometry/Attribute";
import { TypeAssert } from "../../poly/Assert";
import { AttribSetAtIndexSopOperation } from "../../operations/sop/AttribSetAtIndex";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory";
import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils";
const DEFAULT = AttribSetAtIndexSopOperation.DEFAULT_PARAMS;
const _allPoints = [];
class AttribSetAtIndexSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param the point or object index this applies to */
this.index = ParamConfig.INTEGER(DEFAULT.index, {
range: [0, 100],
rangeLocked: [true, false]
});
/** @param the attribute class (geometry or object) */
this.class = ParamConfig.INTEGER(DEFAULT.class, {
menu: {
entries: AttribClassMenuEntries
}
});
/** @param the attribute type (numeric or string) */
this.type = ParamConfig.INTEGER(DEFAULT.type, {
menu: {
entries: AttribTypeMenuEntries
}
});
/** @param the attribute name */
this.name = ParamConfig.STRING(DEFAULT.name);
/** @param the attribute size (1 for float, 2 for vector2, 3 for vector3, 4 for vector4) */
this.size = ParamConfig.INTEGER(DEFAULT.size, {
range: [1, 4],
rangeLocked: [true, true],
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC) }
});
/** @param the value for a float attribute */
this.value1 = ParamConfig.FLOAT(DEFAULT.value1, {
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), size: 1 }
});
/** @param the value for a vector2 */
this.value2 = ParamConfig.VECTOR2(DEFAULT.value2, {
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), size: 2 }
});
/** @param the value for a vector3 */
this.value3 = ParamConfig.VECTOR3(DEFAULT.value3, {
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), size: 3 }
});
/** @param the value for a vector4 */
this.value4 = ParamConfig.VECTOR4(DEFAULT.value4, {
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), size: 4 }
});
/** @param the value for a string attribute */
this.string = ParamConfig.STRING(DEFAULT.string, {
visibleIf: { type: ATTRIBUTE_TYPES.indexOf(AttribType.STRING) }
});
}
}
const ParamsConfig = new AttribSetAtIndexSopParamsConfig();
export class AttribSetAtIndexSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return "attribSetAtIndex";
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(AttribSetAtIndexSopOperation.INPUT_CLONED_STATE);
}
cook(inputCoreGroups) {
const attribName = this.pv.name;
if (this._isUsingExpression()) {
if (attribName && attribName.trim() != "") {
this._addAttribute(ATTRIBUTE_CLASSES[this.pv.class], inputCoreGroups[0]);
} else {
this.states.error.set("attribute name is not valid");
}
} else {
this._operation = this._operation || new AttribSetAtIndexSopOperation(this.scene(), this.states, this);
const coreGroup = this._operation.cook(inputCoreGroups, this.pv);
this.setCoreGroup(coreGroup);
}
}
_addAttribute(attribClass, coreGroup) {
const attribType = ATTRIBUTE_TYPES[this.pv.type];
switch (attribClass) {
case AttribClass.POINT:
this._addPointAttribute(attribType, coreGroup);
return this.setCoreGroup(coreGroup);
case AttribClass.VERTEX:
this.states.error.set("vertex attributes are not supported");
return this.setCoreGroup(coreGroup);
case AttribClass.PRIMITIVE:
this.states.error.set("primitive attributes are not supported");
return this.setCoreGroup(coreGroup);
case AttribClass.OBJECT:
this._addObjectAttribute(attribType, coreGroup);
return this.setCoreGroup(coreGroup);
case AttribClass.CORE_GROUP:
this._addCoreGroupAttribute(attribType, coreGroup);
return this.setCoreGroup(coreGroup);
}
TypeAssert.unreachable(attribClass);
}
_addPointAttribute(attribType, coreGroup) {
const objects = coreGroup.allObjects();
switch (attribType) {
case AttribType.NUMERIC: {
for (const object of objects) {
this._addNumericAttributeToPoints(object);
}
return;
}
case AttribType.STRING: {
for (const object of objects) {
this._addStringAttributeToPoints(object);
}
return;
}
}
TypeAssert.unreachable(attribType);
}
_addObjectAttribute(attribType, coreGroup) {
const allCoreObjects = coreGroup.allCoreObjects();
const attribName = this.pv.name;
const defaultValue = AttribSetAtIndexSopOperation.defaultAttribValue(this.pv);
if (defaultValue != null) {
for (const coreObject2 of allCoreObjects) {
if (!coreObject2.hasAttribute(attribName)) {
coreObject2.setAttribValue(attribName, defaultValue);
}
}
}
const coreObject = allCoreObjects[this.pv.index];
if (!coreObject) {
return;
}
switch (attribType) {
case AttribType.NUMERIC:
this._addNumericAttributeToObject(coreObject);
return;
case AttribType.STRING:
this._addStringAttributeToObject(coreObject);
return;
}
TypeAssert.unreachable(attribType);
}
_addCoreGroupAttribute(attribType, coreGroup) {
switch (attribType) {
case AttribType.NUMERIC:
this._addNumericAttributeToCoreGroup(coreGroup);
return;
case AttribType.STRING:
this._addStringAttributeToCoreGroup(coreGroup);
return;
}
TypeAssert.unreachable(attribType);
}
_addNumericAttributeToPoints(object) {
const corePointClass = corePointClassFactory(object);
const attribName = CoreAttribute.remapName(this.pv.name);
if (!corePointClass.hasAttribute(object, attribName)) {
corePointClass.addNumericAttribute(object, attribName, this.pv.size, 0);
}
const attrib = corePointClass.attribute(object, attribName);
const array = attrib.array;
const { index, size } = this.pv;
switch (size) {
case 1: {
if (index < array.length) {
array[index] = this.pv.value1;
attrib.needsUpdate = true;
}
break;
}
case 2: {
const i2 = index * 2;
if (i2 < array.length) {
this.pv.value2.toArray(array, i2);
attrib.needsUpdate = true;
}
break;
}
case 3: {
const i3 = index * 3;
if (i3 < array.length) {
this.pv.value3.toArray(array, i3);
attrib.needsUpdate = true;
}
break;
}
case 4: {
const i4 = index * 4;
if (i4 < array.length) {
this.pv.value4.toArray(array, i4);
attrib.needsUpdate = true;
}
break;
}
}
}
_addNumericAttributeToObject(coreObject) {
const param = [this.p.value1, this.p.value2, this.p.value3, this.p.value4][this.pv.size - 1];
const attribName = this.pv.name;
coreObject.setAttribValue(attribName, param.value);
}
_addNumericAttributeToCoreGroup(coreGroup) {
const param = [this.p.value1, this.p.value2, this.p.value3, this.p.value4][this.pv.size - 1];
const attribName = this.pv.name;
coreGroup.setAttribValue(attribName, param.value);
}
_addStringAttributeToPoints(object) {
const corePointClass = corePointClassFactory(object);
const attribName = this.pv.name;
if (!corePointClass.hasAttribute(object, attribName)) {
const tmpIndexData = CoreAttribute.arrayToIndexedArrays([""]);
corePointClass.setIndexedAttribute(object, attribName, tmpIndexData["values"], tmpIndexData["indices"]);
}
pointsFromObject(object, _allPoints);
const param = this.p.string;
const stringValues = new Array(_allPoints.length);
for (const point of _allPoints) {
let currentValue = point.stringAttribValue(attribName);
if (currentValue == null) {
currentValue = "";
}
stringValues[point.index()] = currentValue;
}
const indexPoint = _allPoints[this.pv.index];
if (indexPoint) {
stringValues[indexPoint.index()] = param.value;
}
const indexData = CoreAttribute.arrayToIndexedArrays(stringValues);
corePointClass.setIndexedAttribute(object, attribName, indexData["values"], indexData["indices"]);
}
_addStringAttributeToObject(coreObject) {
const param = this.p.string;
const attribName = this.pv.name;
coreObject.setAttribValue(attribName, param.value);
}
_addStringAttributeToCoreGroup(coreGroup) {
const param = this.p.string;
const attribName = this.pv.name;
coreGroup.setAttribValue(attribName, param.value);
}
//
//
// CHECK IF EXPRESSION IS BEING USED, TO ALLOW EASY SWITCH TO OPERATION
//
//
_isUsingExpression() {
const attribType = ATTRIBUTE_TYPES[this.pv.type];
switch (attribType) {
case AttribType.NUMERIC:
const param = [this.p.value1, this.p.value2, this.p.value3, this.p.value4][this.pv.size - 1];
return param.hasExpression();
case AttribType.STRING:
return this.p.string.hasExpression();
}
}
//
//
// API UTILS
//
//
setAttribClass(attribClass) {
this.p.class.set(ATTRIBUTE_CLASSES.indexOf(attribClass));
}
attribClass() {
return ATTRIBUTE_CLASSES[this.pv.class];
}
setAttribType(type) {
this.p.type.set(ATTRIBUTE_TYPES.indexOf(type));
}
attribType() {
return ATTRIBUTE_TYPES[this.pv.type];
}
}