UNPKG

polygonjs-engine

Version:

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

255 lines (254 loc) 7.62 kB
import {Color as Color2} from "three/src/math/Color"; import {CoreGeometry} from "./Geometry"; import {CoreAttribute} from "./Attribute"; import {CoreConstant, AttribType} from "./Constant"; import {CoreMaterial} from "./Material"; import {CoreString} from "../String"; import {CoreEntity} from "./Entity"; import {CoreType} from "../Type"; import {ObjectUtils as ObjectUtils2} from "../ObjectUtils"; const PTNUM = "ptnum"; const NAME_ATTR = "name"; const ATTRIBUTES = "attributes"; export class CoreObject extends CoreEntity { constructor(_object, index) { super(index); this._object = _object; if (this._object.userData[ATTRIBUTES] == null) { this._object.userData[ATTRIBUTES] = {}; } } object() { return this._object; } geometry() { return this._object.geometry; } coreGeometry() { const geo = this.geometry(); if (geo) { return new CoreGeometry(geo); } else { return null; } } points() { return this.coreGeometry()?.points() || []; } pointsFromGroup(group) { if (group) { const indices = CoreString.indices(group); if (indices) { const points = this.points(); return indices.map((i) => points[i]); } else { return []; } } else { return this.points(); } } static isInGroup(groupString, object) { const group = groupString.trim(); if (group.length == 0) { return true; } const elements = group.split("="); const attribNameWithPrefix = elements[0]; if (attribNameWithPrefix[0] == "@") { const attribName = attribNameWithPrefix.substr(1); const expectedAttribValue = elements[1]; const currentAttribValue = this.attribValue(object, attribName); return expectedAttribValue == currentAttribValue; } return false; } computeVertexNormals() { this.coreGeometry()?.computeVertexNormals(); } static addAttribute(object, attrib_name, value) { let data; if (value != null && !CoreType.isNumber(value) && !CoreType.isArray(value) && !CoreType.isString(value)) { data = value.toArray(); } else { data = value; } const user_data = object.userData; user_data[ATTRIBUTES] = user_data[ATTRIBUTES] || {}; user_data[ATTRIBUTES][attrib_name] = data; } addAttribute(name, value) { CoreObject.addAttribute(this._object, name, value); } addNumericAttrib(name, value) { this.addAttribute(name, value); } setAttribValue(name, value) { this.addAttribute(name, value); } addNumericVertexAttrib(name, size, default_value) { if (default_value == null) { default_value = CoreAttribute.default_value(size); } this.coreGeometry()?.addNumericAttrib(name, size, default_value); } attributeNames() { return Object.keys(this._object.userData[ATTRIBUTES]); } attribNames() { return this.attributeNames(); } hasAttrib(name) { return this.attributeNames().includes(name); } renameAttrib(old_name, new_name) { const current_value = this.attribValue(old_name); if (current_value != null) { this.addAttribute(new_name, current_value); this.deleteAttribute(old_name); } else { console.warn(`attribute ${old_name} not found`); } } deleteAttribute(name) { delete this._object.userData[ATTRIBUTES][name]; } static attribValue(object, name, index = 0, target) { if (name === PTNUM) { return index; } if (object.userData && object.userData[ATTRIBUTES]) { const val = object.userData[ATTRIBUTES][name]; if (val == null) { if (name == NAME_ATTR) { return object.name; } } else { if (CoreType.isArray(val) && target) { target.fromArray(val); return target; } } return val; } if (name == NAME_ATTR) { return object.name; } } static stringAttribValue(object, name, index = 0) { const str = this.attribValue(object, name, index); if (str != null) { if (CoreType.isString(str)) { return str; } else { return `${str}`; } } } attribValue(name, target) { return CoreObject.attribValue(this._object, name, this._index, target); } stringAttribValue(name) { return CoreObject.stringAttribValue(this._object, name, this._index); } name() { return this.attribValue(NAME_ATTR); } humanType() { return CoreConstant.CONSTRUCTOR_NAMES_BY_CONSTRUCTOR_NAME[this._object.constructor.name]; } attribTypes() { const h = {}; for (let attrib_name of this.attribNames()) { const type = this.attribType(attrib_name); if (type != null) { h[attrib_name] = type; } } return h; } attribType(name) { const val = this.attribValue(name); if (CoreType.isString(val)) { return AttribType.STRING; } else { return AttribType.NUMERIC; } } attribSizes() { const h = {}; for (let attrib_name of this.attribNames()) { const size = this.attribSize(attrib_name); if (size != null) { h[attrib_name] = size; } } return h; } attribSize(name) { const val = this.attribValue(name); if (val == null) { return null; } return CoreAttribute.attribSizeFromValue(val); } clone() { return CoreObject.clone(this._object); } static clone(src_object) { const new_object = src_object.clone(); var sourceLookup = new Map(); var cloneLookup = new Map(); CoreObject.parallelTraverse(src_object, new_object, function(sourceNode, clonedNode) { sourceLookup.set(clonedNode, sourceNode); cloneLookup.set(sourceNode, clonedNode); }); new_object.traverse(function(node) { const src_node = sourceLookup.get(node); const mesh_node = node; if (mesh_node.geometry) { const src_node_geometry = src_node.geometry; mesh_node.geometry = CoreGeometry.clone(src_node_geometry); const mesh_node_geometry = mesh_node.geometry; if (mesh_node_geometry.userData) { mesh_node_geometry.userData = ObjectUtils2.cloneDeep(src_node_geometry.userData); } } if (mesh_node.material) { mesh_node.material = src_node.material; CoreMaterial.apply_custom_materials(node, mesh_node.material); const material_with_color = mesh_node.material; if (material_with_color.color == null) { material_with_color.color = new Color2(1, 1, 1); } } if (src_object.userData) { node.userData = ObjectUtils2.cloneDeep(src_node.userData); } const src_node_with_animations = src_node; if (src_node_with_animations.animations) { node.animations = src_node_with_animations.animations.map((animation) => animation.clone()); } const skinned_node = node; if (skinned_node.isSkinnedMesh) { var clonedMesh = skinned_node; var sourceMesh = src_node; var sourceBones = sourceMesh.skeleton.bones; clonedMesh.skeleton = sourceMesh.skeleton.clone(); clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix); const new_bones = sourceBones.map(function(bone) { return cloneLookup.get(bone); }); clonedMesh.skeleton.bones = new_bones; clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix); } }); return new_object; } static parallelTraverse(a, b, callback) { callback(a, b); for (var i = 0; i < a.children.length; i++) { this.parallelTraverse(a.children[i], b.children[i], callback); } } }