polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
255 lines (254 loc) • 7.62 kB
JavaScript
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);
}
}
}