UNPKG

@polygonjs/polygonjs

Version:

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

460 lines (459 loc) 14 kB
"use strict"; import { Vector4, Vector3, Vector2 } from "three"; import { Attribute, CoreAttribute } from "../../Attribute"; import { isArray } from "../../../Type"; import { CoreEntityWithObject } from "../../CoreEntity"; import { DOT, COMPONENT_INDICES, AttribType, AttribClass } from "../../Constant"; import { coreObjectInstanceFactory } from "../../CoreObjectFactory"; import { TypeAssert } from "../../../../engine/poly/Assert"; import { uniqRelatedEntityIds } from "../utils/Common"; const _relatedPrimitiveIds = []; function _warnOverloadRequired(functionName) { console.warn(`CorePoint.${functionName} needs to be overloaded`); } export class CorePoint extends CoreEntityWithObject { // protected _object?: ObjectContent<T>; // constructor(object?: ObjectContent<T>, index?: number) { // super(object, index); // this._object = object; // } builder() { return void 0; } static addAttribute(object, attribName, attribute) { _warnOverloadRequired("addAttribute"); } static entitiesCount(object) { return 0; } static attributes(object) { _warnOverloadRequired("attributes"); return; } attributes() { return this.constructor.attributes(this._object); } static attribute(object, attribName) { const attributes = this.attributes(object); if (!attributes) { return; } return attributes[attribName]; } attribute(attribName) { return this.constructor.attribute(this._object, attribName); } static attribSize(object, attribName) { const attributes = this.attributes(object); if (!attributes) { return -1; } attribName = CoreAttribute.remapName(attribName); return attributes[attribName].itemSize || 0; } attribSize(attribName) { return this.constructor.attribSize(this._object, attribName); } static hasAttribute(object, attribName) { const remappedName = CoreAttribute.remapName(attribName); return this.attributes(object) ? this.attributes(object)[remappedName] != null : false; } hasAttribute(attribName) { return this.constructor.hasAttribute(this._object, attribName); } // // // INDEXED ATTRIBUTES // // static userDataAttribs(object) { _warnOverloadRequired("userDataAttribs"); return {}; } userDataAttribs() { return this._object ? this.constructor.userDataAttribs(this._object) : {}; } static userDataAttrib(object, attribName) { attribName = CoreAttribute.remapName(attribName); return this.userDataAttribs(object)[attribName]; } userDataAttrib(name) { name = CoreAttribute.remapName(name); return this.userDataAttribs()[name]; } static attributeNames(object) { const attributes = this.attributes(object); if (!attributes) { return []; } return Object.keys(attributes); } static attributeNamesMatchingMask(object, masksString) { return CoreAttribute.attribNamesMatchingMask(masksString, this.attributeNames(object)); } static indexedAttributeNames(object) { return object ? Object.keys(this.userDataAttribs(object) || {}) : []; } indexedAttributeNames() { return this._object ? this.constructor.indexedAttributeNames(this._object) : []; } static isAttribIndexed(object, attribName) { attribName = CoreAttribute.remapName(attribName); return this.userDataAttrib(object, attribName) != null; } isAttribIndexed(name) { name = CoreAttribute.remapName(name); return this.userDataAttrib(name) != null; } static setIndexedAttributeValues(object, attribName, values) { this.userDataAttribs(object)[attribName] = values; } setIndexedAttributeValues(attribName, values) { return this.constructor.setIndexedAttributeValues(this._object, attribName, values); } static setIndexedAttribute(object, attribName, values, indices) { _warnOverloadRequired("setIndexedAttribute"); } setIndexedAttribute(attribName, values, indices) { return this.constructor.setIndexedAttribute(this._object, attribName, values, indices); } // static indexedAttribValue(object, index, attribName) { const valueIndex = this.attribValueIndex(object, index, attribName); const values = this.userDataAttrib(object, attribName); return values ? values[valueIndex] : null; } indexedAttribValue(attribName) { return this.constructor.indexedAttribValue(this._object, this._index, attribName); } static stringAttribValue(object, index, attribName) { return this.indexedAttribValue(object, index, attribName); } stringAttribValue(attribName) { return this.indexedAttribValue(attribName); } static attribValueIndex(object, index, attribName) { _warnOverloadRequired("attribValueIndex"); return 0; } attribValueIndex(attribName) { return this.constructor.attribValueIndex(this._object, this._index, attribName); } static attribType(object, attribName) { if (this.isAttribIndexed(object, attribName)) { return AttribType.STRING; } else { return AttribType.NUMERIC; } } attribType(attribName) { return this.constructor.attribType(this._object, attribName); } isStringAttribute(attribName) { return this.attribType(attribName) == AttribType.STRING; } setAttribIndex(attribName, newValueIndex) { const attribute = this.attribute(attribName); if (!attribute) { return; } const array = attribute.array; array[this._index] = newValueIndex; return; } // // // // // static renameAttribute(object, oldName, newName) { const attributes = this.attributes(object); if (!attributes) { return; } const attribute = this.attribute(object, oldName); if (!attribute) { return; } attributes[newName] = attribute; delete attributes[oldName]; } static deleteAttribute(object, attribName) { const attributes = this.attributes(object); if (!attributes) { return; } delete attributes[attribName]; } // // // // // static attribValue(object, index, attribName, target) { if (attribName === Attribute.POINT_INDEX) { return index; } else { let componentName = null; let componentIndex = null; if (attribName[attribName.length - 2] === DOT) { componentName = attribName[attribName.length - 1]; componentIndex = COMPONENT_INDICES[componentName]; attribName = attribName.substring(0, attribName.length - 2); } const remapedName = CoreAttribute.remapName(attribName); const attrib = this.attribute(object, remapedName); if (attrib) { const { array } = attrib; if (this.isAttribIndexed(object, remapedName)) { return this.indexedAttribValue(object, index, remapedName); } else { const itemSize = attrib.itemSize; const startIndex = index * itemSize; if (componentIndex == null) { switch (itemSize) { case 1: return array[startIndex]; break; case 2: target = target || new Vector2(); target.fromArray(array, startIndex); return target; break; case 3: target = target || new Vector3(); target.fromArray(array, startIndex); return target; break; case 4: target = target || new Vector4(); target.fromArray(array, startIndex); return target; break; default: throw `size not valid (${itemSize})`; } } else { switch (itemSize) { case 1: return array[startIndex]; break; default: return array[startIndex + componentIndex]; } } } } else { const attributesDict = this.attributes() || {}; const attribNames = Object.keys(attributesDict); const message = `attrib ${attribName} not found. availables are: ${attribNames.join(",")}`; console.warn(message); throw message; } } } attribValue(attribName, target) { return this.constructor.attribValue(this._object, this._index, attribName, target); } attribValueNumber(attribName) { const attrib = this.attribute(attribName); if (!attrib) { return 0; } return attrib.array[this._index]; } attribValueVector2(attribName, target) { const attrib = this.attribute(attribName); if (!attrib) { return; } target.fromArray(attrib.array, this._index * 2); return target; } attribValueVector3(attribName, target) { const attrib = this.attribute(attribName); if (!attrib) { return; } target.fromArray(attrib.array, this._index * 3); return target; } attribValueVector4(attribName, target) { const attrib = this.attribute(attribName); if (!attrib) { return; } target.fromArray(attrib.array, this._index * 4); return target; } position(target) { _warnOverloadRequired("position"); return target; } setPosition(newPosition) { this.setAttribValueFromVector3(Attribute.POSITION, newPosition); } normal(target) { _warnOverloadRequired("normal"); return target; } setNormal(newNormal) { return this.setAttribValueFromVector3(Attribute.NORMAL, newNormal); } static computeNormals(object) { _warnOverloadRequired("computeNormals"); } setAttribValue(attribName, value) { const attrib = this.attribute(attribName); if (!attrib) { return; } const array = attrib.array; const attribSize = attrib.itemSize; if (isArray(value)) { for (let i = 0; i < attribSize; i++) { array[this._index * attribSize + i] = value[i]; } return; } switch (attribSize) { case 1: array[this._index] = value; break; case 2: const v2 = value; const i2 = this._index * 2; array[i2 + 0] = v2.x; array[i2 + 1] = v2.y; break; case 3: const isColor = value.r != null; const i3 = this._index * 3; if (isColor) { const col = value; array[i3 + 0] = col.r; array[i3 + 1] = col.g; array[i3 + 2] = col.b; } else { const v3 = value; array[i3 + 0] = v3.x; array[i3 + 1] = v3.y; array[i3 + 2] = v3.z; } break; case 4: const v4 = value; const i4 = this._index * 4; array[i4 + 0] = v4.x; array[i4 + 1] = v4.y; array[i4 + 2] = v4.z; array[i4 + 3] = v4.w; break; default: console.warn(`CorePoint.setAttribValue does not yet allow attrib size ${attribSize}`); throw `attrib size ${attribSize} not implemented`; } } setAttribValueFromNumber(attribName, value) { const attrib = this.attribute(attribName); if (!attrib) { return; } const array = attrib.array; array[this._index] = value; } setAttribValueFromVector2(attribName, value) { const attrib = this.attribute(attribName); if (!attrib || this.isStringAttribute(attribName)) { return; } value.toArray(attrib.array, this._index * 2); } setAttribValueFromVector3(attribName, value) { const attrib = this.attribute(attribName); if (!attrib || this.isStringAttribute(attribName)) { return; } value.toArray(attrib.array, this._index * 3); } setAttribValueFromVector4(attribName, value) { const attrib = this.attribute(attribName); if (!attrib || this.isStringAttribute(attribName)) { return; } value.toArray(attrib.array, this._index * 4); } // static addAttributeFromAttribData(object, attribName, attribData) { switch (attribData.type()) { case AttribType.STRING: return console.log("TODO: to implement"); case AttribType.NUMERIC: return this.addNumericAttribute(object, attribName, attribData.size()); } } static addNumericAttribute(object, attribName, size = 1, defaultValue = 0) { _warnOverloadRequired("addNumericAttribute"); } // static markAttribAsNeedsUpdate(object, attribName) { _warnOverloadRequired("markAttribAsNeedsUpdate"); } // // // RELATED ENTITIES // // static relatedPrimitiveIds(object, pointIndex, target, traversedRelatedEntityData) { const ids = traversedRelatedEntityData ? traversedRelatedEntityData[AttribClass.VERTEX].ids : _relatedPrimitiveIds; this.relatedVertexIds(object, pointIndex, ids); uniqRelatedEntityIds( ids, (vertexId, relatedEntityIds) => { this.relatedVertexClass(object).relatedPrimitiveIds(object, vertexId, relatedEntityIds); }, target ); } static relatedPrimitiveClass(object) { return this.relatedVertexClass(object).relatedPrimitiveClass(object); } static relatedObjectClass(object) { return this.relatedPrimitiveClass(object).relatedObjectClass(object); } relatedEntities(attribClass, coreGroup, target, traversedRelatedEntityData) { switch (attribClass) { case AttribClass.POINT: { target.length = 1; target[0] = this; return; } case AttribClass.VERTEX: { return this.relatedVertices(target, traversedRelatedEntityData); } case AttribClass.PRIMITIVE: { return this.relatedPrimitives(target, traversedRelatedEntityData); } case AttribClass.OBJECT: { if (this._object) { target.length = 1; target[0] = coreObjectInstanceFactory(this._object); } else { target.length = 0; } return; } case AttribClass.CORE_GROUP: { target.length = 1; target[0] = coreGroup; return; } } TypeAssert.unreachable(attribClass); } }