@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
543 lines (542 loc) • 16.6 kB
JavaScript
"use strict";
import { Color, Vector2, Vector3, Vector4 } from "three";
import { Attribute, CoreAttribute } from "../../Attribute";
import { AttribType, AttribClass } from "../../Constant";
import { CoreEntityWithObject } from "../../CoreEntity";
import { isArray, isVector, isColor, isString } from "../../../Type";
import { EntityGroupCollection } from "../../EntityGroupCollection";
import { _updateObjectAttribRef } from "../../../reactivity/ObjectAttributeReactivityUpdateRef";
import { attribValueNonPrimitive, copyAttribValue, cloneAttribValue, uniqRelatedEntityIds } from "../utils/Common";
import { getOrCreateObjectAttributeRef } from "../../../reactivity/ObjectAttributeReactivityCreateRef";
import { watch } from "../../../reactivity/CoreReactivity";
import { objectData } from "./BaseCoreObjectUtils";
import { TypeAssert } from "../../../../engine/poly/Assert";
var PropertyName = /* @__PURE__ */ ((PropertyName2) => {
PropertyName2["NAME"] = "name";
PropertyName2["POSITION"] = "position";
return PropertyName2;
})(PropertyName || {});
const ATTRIBUTES = "attributes";
const ORIGIN = new Vector3(0, 0, 0);
function _convertArrayToVector(value) {
switch (value.length) {
case 1:
return value[0];
case 2:
return new Vector2(value[0], value[1]);
case 3:
return new Vector3(value[0], value[1], value[2]);
case 4:
return new Vector4(value[0], value[1], value[2], value[3]);
}
}
const tmpVec3 = new Vector3();
const tmpN3 = [0, 0, 0];
const _relatedPrimitiveIds = [];
const _relatedVertexIds = [];
export class BaseCoreObject extends CoreEntityWithObject {
dispose() {
}
// set_index(i: number) {
// this._index = i;
// }
geometry() {
var _a;
return ((_a = this._object) == null ? void 0 : _a.geometry) || null;
}
builder() {
return void 0;
}
static attributeRef(object, attribName, type, defaultValue) {
return getOrCreateObjectAttributeRef(object, attribName, type, defaultValue);
}
attributeRef(attribName, type, defaultValue) {
if (!this._object) {
return;
}
return this.constructor.attributeRef(
this._object,
attribName,
type,
defaultValue
);
}
static onAttribChange(object, attribName, type, defaultValue, callback) {
const ref = this.attributeRef(object, attribName, type, defaultValue);
return watch(ref.current, callback);
}
onAttribChange(attribName, type, defaultValue, callback) {
if (!this._object) {
return;
}
return this.constructor.onAttribChange(
this._object,
attribName,
type,
defaultValue,
callback
);
}
static setAttribute(object, attribName, value) {
this.addAttribute(object, attribName, value);
}
static addAttribute(object, attribName, value) {
if (isArray(value)) {
const convertedValue = _convertArrayToVector(value);
if (!convertedValue) {
const message = `value invalid`;
console.error(message, value);
throw new Error(message);
}
}
const dict = this._attributesDictionary(object);
const currentValue = dict[attribName];
if (attribValueNonPrimitive(value)) {
if (currentValue == null) {
const cloned = cloneAttribValue(value);
if (cloned) {
dict[attribName] = cloned;
}
} else {
if (attribValueNonPrimitive(currentValue)) {
copyAttribValue(value, currentValue);
}
}
} else {
dict[attribName] = value;
}
_updateObjectAttribRef(object, attribName, value);
}
static addNumericAttribute(object, attribName, size = 1, defaultValue = 0) {
this.addAttribute(object, attribName, defaultValue);
}
addAttribute(name, value) {
if (!this._object) {
return;
}
this.constructor.addAttribute(this._object, name, value);
}
addNumericAttrib(name, value) {
if (!this._object) {
return;
}
this.constructor.addNumericAttribute(
this._object,
name,
1,
value
);
}
setAttribValue(name, value) {
this.addAttribute(name, value);
}
// addNumericVertexAttrib(name: string, size: number, defaultValue: NumericAttribValue) {
// // if (defaultValue == null) {
// // defaultValue = CoreAttribute.default_value(size);
// // }
// // this.coreGeometry()?.addNumericAttrib(name, size, defaultValue);
// }
static _attributesDictionary(object) {
return object.userData[ATTRIBUTES] || this._createAttributesDictionaryIfNone(object);
}
static attributesDictionaryEntry(object, attribName, defaultValue) {
const dict = object.userData[ATTRIBUTES] || this._createAttributesDictionaryIfNone(object);
let entry = dict[attribName];
if (entry == null && defaultValue != null) {
entry = defaultValue;
dict[attribName] = entry;
}
return entry;
}
// static attributesPreviousValuesDictionary<T extends CoreObjectType>(object: ObjectContent<T>) {
// return (
// (object.userData[ATTRIBUTES_PREVIOUS_VALUES] as AttributeDictionary) ||
// this._createAttributesPreviousValuesDictionaryIfNone(object)
// );
// }
static _createAttributesDictionaryIfNone(object) {
if (!object.userData[ATTRIBUTES]) {
return object.userData[ATTRIBUTES] = {};
}
}
// private static _createAttributesPreviousValuesDictionaryIfNone<T extends CoreObjectType>(object: ObjectContent<T>) {
// if (!object.userData[ATTRIBUTES_PREVIOUS_VALUES]) {
// return (object.userData[ATTRIBUTES_PREVIOUS_VALUES] = {});
// }
// }
_attributesDictionary() {
return this.constructor._attributesDictionary(this._object);
}
static attributes(object) {
return this._attributesDictionary(object);
}
attributes() {
if (!this._object) {
return;
}
return this.constructor.attributes(this._object);
}
attributeNames() {
return this.attribNames();
}
static attribNames(object) {
return Object.keys(this._attributesDictionary(object));
}
attribNames() {
return this.constructor.attribNames(this._object);
}
static hasAttribute(object, attribName) {
return attribName in this._attributesDictionary(object);
}
hasAttribute(attribName) {
return this.constructor.hasAttribute(
this._object,
attribName
);
}
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));
}
renameAttribute(oldName, newName) {
return this.constructor.renameAttribute(
this._object,
oldName,
newName
);
}
static renameAttribute(object, oldName, newName) {
const currentValue = this.attribValue(object, oldName);
if (currentValue != null) {
this.addAttribute(object, newName, currentValue);
this.deleteAttribute(object, oldName);
} else {
console.warn(`attribute ${oldName} not found`);
}
}
deleteAttribute(name) {
delete this._attributesDictionary()[name];
}
static deleteAttribute(object, attribName) {
delete this._attributesDictionary(object)[attribName];
}
// static position:PositionStaticMethod<CoreObjectType> = DEFAULT_POSITION_STATIC_METHOD
static position(object, target) {
target.copy(ORIGIN);
}
position(target) {
this.constructor.position(this._object, target);
return target;
}
static boundingBox(object, target) {
target.makeEmpty();
}
boundingBox(target) {
this.constructor.boundingBox(this._object, target);
}
static geometryBoundingBox(object, target) {
this.boundingBox(object, target);
}
geometryBoundingBox(target) {
this.constructor.geometryBoundingBox(this._object, target);
}
static boundingSphere(object, target) {
target.makeEmpty();
}
boundingSphere(target) {
this.constructor.boundingSphere(this._object, target);
}
static geometryBoundingSphere(object, target) {
target.makeEmpty();
}
geometryBoundingSphere(target) {
this.constructor.geometryBoundingSphere(this._object, target);
}
static attribValue(object, attribName, index = 0, target) {
const _attribFromProperty = () => {
if (attribName == "name" /* NAME */) {
return object.name;
}
if (attribName == "position" /* POSITION */) {
const _target = target instanceof Vector3 ? target : tmpVec3;
this.position(object, _target);
_target.toArray(tmpN3);
return tmpN3;
}
};
if (attribName === Attribute.OBJECT_INDEX) {
return index;
}
if (attribName === Attribute.OBJECT_NAME) {
return object.name;
}
if (object.userData) {
const val = this.attributesDictionaryEntry(object, attribName);
if (val == null) {
return _attribFromProperty();
} else {
if (isVector(val) && target) {
if (val instanceof Vector2 && target instanceof Vector2) {
return target.copy(val);
}
if (val instanceof Vector3 && target instanceof Vector3) {
return target.copy(val);
}
if (val instanceof Vector4 && target instanceof Vector4) {
return target.copy(val);
}
}
if (isColor(val) && target) {
if (val instanceof Color && target instanceof Color) {
return target.copy(val);
}
}
if (isArray(val) && target) {
target.fromArray(val);
return target;
}
}
return val;
}
return _attribFromProperty();
}
// static previousAttribValue<T extends CoreObjectType>(
// object: ObjectContent<T>,
// attribName: string
// ): AttribValue | undefined {
// const dict = this.attributesPreviousValuesDictionary(object);
// return dict[attribName];
// }
static stringAttribValue(object, attribName, index = 0) {
const str = this.attribValue(object, attribName, index);
if (str != null) {
if (isString(str)) {
return str;
} else {
return `${str}`;
}
}
return null;
}
// static makeAttribReactive<V extends AttribValue, T extends CoreObjectType>(
// object: ObjectContent<T>,
// attribName: string,
// callback: AttributeReactiveCallback<V>
// ) {
// const attributesDict = this.attributesDictionary(object);
// // const attributesPreviousValuesDict = this.attributesPreviousValuesDictionary(object);
// const currentValue = attributesDict[attribName];
// if (currentValue instanceof Vector4) {
// return makeAttribReactiveVector4(
// object,
// attribName,
// (<unknown>callback) as AttributeReactiveCallback<Vector4>
// );
// }
// if (currentValue instanceof Vector3) {
// return makeAttribReactiveVector3(
// object,
// attribName,
// (<unknown>callback) as AttributeReactiveCallback<Vector3>
// );
// }
// if (currentValue instanceof Vector2) {
// return makeAttribReactiveVector2(
// object,
// attribName,
// (<unknown>callback) as AttributeReactiveCallback<Vector2>
// );
// }
// return makeAttribReactiveSimple(
// object,
// attribName,
// (<unknown>callback) as AttributeReactiveCallback<string | number>
// );
// // // create a dummy val in case there is no attribute yet
// // if (attributesDict[attribName] == null) {
// // attributesDict[attribName] = 0;
// // }
// // const proxy: AttributeProxy<V> = {
// // value: attributesDict[attribName] as V,
// // previousValue: attributesDict[attribName] as V,
// // };
// // Object.defineProperties(attributesDict, {
// // [attribName]: {
// // get: function () {
// // return proxy.value;
// // },
// // set: function (x) {
// // if (x != proxy.value) {
// // proxy.previousValue = proxy.value;
// // proxy.value = x;
// // callback(proxy.value, proxy.previousValue);
// // }
// // return proxy.value;
// // },
// // configurable: true,
// // },
// // });
// // Object.defineProperties(attributesPreviousValuesDict, {
// // [attribName]: {
// // get: function () {
// // return proxy.previousValue;
// // },
// // configurable: true,
// // },
// // });
// }
attribValue(attribName, target) {
return this.constructor.attribValue(
this._object,
attribName,
this._index,
target
);
}
stringAttribValue(name) {
return this.constructor.stringAttribValue(
this._object,
name,
this._index
);
}
name() {
return this.attribValue("name" /* NAME */);
}
humanType() {
return this._object.type;
}
attribTypes() {
const h = {};
for (const attrib_name of this.attribNames()) {
const type = this.attribType(attrib_name);
if (type != null) {
h[attrib_name] = type;
}
}
return h;
}
static attribType(object, attribName) {
const val = this.attribValue(object, attribName);
if (isString(val)) {
return AttribType.STRING;
} else {
return AttribType.NUMERIC;
}
}
attribType(attribName) {
return this.constructor.attribType(this._object, attribName);
}
attribSizes() {
const h = {};
const attribNames = this.attribNames();
for (const attribName of attribNames) {
const size = this.attribSize(attribName);
if (size != null) {
h[attribName] = size;
}
}
return h;
}
static attribSize(object, attribName) {
const val = this.attribValue(object, attribName);
if (val == null) {
return null;
}
return CoreAttribute.attribSizeFromValue(val);
}
attribSize(attribName) {
return this.constructor.attribSize(this._object, attribName);
}
static objectData(object) {
return objectData(object);
}
clone() {
const clonedObject = this.constructor.clone(this._object);
const cloned = new this.constructor(clonedObject, this._index);
return cloned;
}
static clone(srcObject) {
return srcObject.clone();
}
static applyMatrix(object, matrix, transformTargetType, transformSpace, transformMode) {
console.warn("applyMatrix.override required", this);
}
static mergeCompact(options) {
console.warn("mergeCompact.override required", this);
}
//
//
// ENTITY GROUPS
//
//
groupCollection() {
return new EntityGroupCollection(this._object);
}
//
//
// RELATED ENTITIES
//
//
static relatedVertexIds(object, objectIndex, target, traversedRelatedEntityData) {
const ids = traversedRelatedEntityData ? traversedRelatedEntityData[AttribClass.PRIMITIVE].ids : _relatedPrimitiveIds;
this.relatedPrimitiveIds(object, objectIndex, ids, traversedRelatedEntityData);
uniqRelatedEntityIds(
ids,
(primitiveId, relatedEntityIds) => {
this.relatedPrimitiveClass(object).relatedVertexIds(object, primitiveId, relatedEntityIds);
},
target
);
}
static relatedPointIds(object, objectIndex, target, traversedRelatedEntityData) {
const ids = traversedRelatedEntityData ? traversedRelatedEntityData[AttribClass.VERTEX].ids : _relatedVertexIds;
this.relatedVertexIds(object, objectIndex, ids, traversedRelatedEntityData);
uniqRelatedEntityIds(
ids,
(vertexId, relatedEntityIds) => {
this.relatedVertexClass(object).relatedPointIds(object, vertexId, relatedEntityIds);
},
target
);
}
relatedEntities(attribClass, coreGroup, target, traversedRelatedEntityData) {
switch (attribClass) {
case AttribClass.POINT: {
this.relatedPoints(target, traversedRelatedEntityData);
return;
}
case AttribClass.VERTEX: {
this.relatedVertices(target, traversedRelatedEntityData);
return;
}
case AttribClass.PRIMITIVE: {
this.relatedPrimitives(target, traversedRelatedEntityData);
return;
}
case AttribClass.OBJECT: {
target.length = 1;
target[0] = this;
return;
}
case AttribClass.CORE_GROUP: {
target.length = 1;
target[0] = coreGroup;
return;
}
}
TypeAssert.unreachable(attribClass);
}
static relatedPointClass(object) {
return this.relatedVertexClass(object).relatedPointClass(object);
}
static relatedVertexClass(object) {
return this.relatedPrimitiveClass(object).relatedVertexClass(object);
}
}