polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
462 lines (432 loc) • 12.2 kB
text/typescript
import {NumericAttribValue, PolyDictionary} from '../../types/GlobalTypes';
import {Vector3} from 'three/src/math/Vector3';
import {Points} from 'three/src/objects/Points';
import {Object3D} from 'three/src/core/Object3D';
import {Mesh} from 'three/src/objects/Mesh';
import {LineSegments} from 'three/src/objects/LineSegments';
import {Group} from 'three/src/objects/Group';
import {BufferGeometry} from 'three/src/core/BufferGeometry';
import {Box3} from 'three/src/math/Box3';
import {CoreObject} from './Object';
import {CoreGeometry} from './Geometry';
import {CoreAttribute} from './Attribute';
import {CoreString} from '../String';
import {CoreConstant, AttribClass, AttribSize, ObjectData, objectTypeFromConstructor} from './Constant';
import {CoreType} from '../Type';
import {ArrayUtils} from '../ArrayUtils';
export type GroupString = string;
export interface Object3DWithGeometry extends Object3D {
geometry: BufferGeometry;
}
export class CoreGroup {
// _group: Group
private _timestamp: number | undefined;
// _core_objects:
private _objects: Object3D[] = [];
private _objects_with_geo: Object3DWithGeometry[] = [];
private _core_objects: CoreObject[] | undefined;
// _geometries: BufferGeometry[];
private _core_geometries: CoreGeometry[] | undefined;
private _bounding_box: Box3 | undefined;
// private _bounding_sphere: Sphere | undefined;
constructor() {
//_group: Group){
// this._group = _group;
this.touch();
}
//
//
// TIMESTAMP
//
//
timestamp() {
return this._timestamp;
}
touch() {
this._timestamp = performance.now();
this.reset();
}
reset() {
this._bounding_box = undefined;
// this._bounding_sphere = undefined;
this._core_geometries = undefined;
this._core_objects = undefined;
}
//
//
// CLONE
//
//
clone() {
const core_group = new CoreGroup();
if (this._objects) {
const objects = [];
for (let object of this._objects) {
objects.push(CoreObject.clone(object));
}
core_group.setObjects(objects);
}
return core_group;
}
//
//
// OBJECTS
//
//
setObjects(objects: Object3D[]) {
this._objects = objects;
this._objects_with_geo = objects.filter((obj) => (obj as Mesh).geometry != null) as Object3DWithGeometry[];
this.touch();
}
objects() {
return this._objects;
}
objectsWithGeo() {
return this._objects_with_geo;
}
coreObjects() {
return (this._core_objects = this._core_objects || this._create_core_objects());
}
private _create_core_objects(): CoreObject[] {
// const list: CoreObject[] = [];
// if (this._objects) {
// for (let i = 0; i < this._objects.length; i++) {
// this._objects[i].traverse((object) => {
// const core_object = new CoreObject(object, i);
// list.push(core_object);
// });
// }
// }
if (this._objects) {
return this._objects.map((object, i) => new CoreObject(object, i));
}
return [];
// return list;
}
objectsData(): ObjectData[] {
if (this._objects) {
return this._objects.map((object) => this._objectData(object));
}
return [];
}
private _objectData(object: Object3D): ObjectData {
let points_count = 0;
if ((object as Mesh).geometry) {
points_count = CoreGeometry.pointsCount((object as Mesh).geometry as BufferGeometry);
}
return {
type: objectTypeFromConstructor(object.constructor),
name: object.name,
children_count: object.children.length,
points_count: points_count,
};
}
// group() {
// return this._group;
// }
// uuid() {
// return this._group.uuid;
// }
geometries(): BufferGeometry[] {
// this._geometries = [];
// for (let object of this._objects) {
// object.traverse((object) => this.__geometry_from_object.bind(this)(this._geometries, object));
// // const geometry = this.geometry_from_object(object)
// // if (geometry != null) {
// // return list.push(new CoreGeometry(geometry));
// // }
// // });
// }
// return this._geometries;
const list: BufferGeometry[] = [];
for (let core_object of this.coreObjects()) {
const geometry = (core_object.object() as Mesh).geometry as BufferGeometry;
if (geometry) {
list.push(geometry);
}
}
return list;
}
coreGeometries(): CoreGeometry[] {
return (this._core_geometries = this._core_geometries || this._createCoreGeometries());
}
private _createCoreGeometries() {
const list: CoreGeometry[] = [];
for (let geometry of this.geometries()) {
list.push(new CoreGeometry(geometry));
// object.traverse(object=> this.__core_geometry_from_object.bind(this)(this._core_geometries, object))
// const geometry = this.geometry_from_object(object)
// if (geometry != null) {
// return list.push(new CoreGeometry(geometry));
// }
// });
}
return list;
}
// __geometry_from_object(list: BufferGeometry[], object: Mesh) {
// if (object.geometry) {
// return list.push(object.geometry as BufferGeometry);
// }
// }
// __core_geometry_from_object(list, object){
// const geometry = CoreGroup.geometry_from_object(object)
// if (geometry != null) {
// return list.push(new CoreGeometry(geometry));
// }
// }
static geometryFromObject(object: Object3D): BufferGeometry | null {
if ((object as Mesh).isMesh || (object as LineSegments).isLine || (object as Points).isPoints) {
return (object as Mesh).geometry as BufferGeometry;
}
return null;
}
faces() {
return this.coreGeometries()
.map((g) => g.faces())
.flat();
}
points() {
return this.coreGeometries()
.map((g) => g.points())
.flat();
}
pointsCount() {
return ArrayUtils.sum(this.coreGeometries().map((g) => g.pointsCount()));
}
totalPointsCount() {
if (this._objects) {
let sum = 0;
for (let object of this._objects) {
object.traverse((object) => {
const geometry = (object as Mesh).geometry as BufferGeometry;
if (geometry) {
sum += CoreGeometry.pointsCount(geometry);
}
});
}
return sum;
} else {
return 0;
}
}
pointsFromGroup(group: GroupString) {
if (group) {
const indices = CoreString.indices(group);
const points = this.points();
return ArrayUtils.compact(indices.map((i) => points[i]));
} else {
return this.points();
}
}
static _fromObjects(objects: Object3D[]): CoreGroup {
const core_group = new CoreGroup();
core_group.setObjects(objects);
return core_group;
}
objectsFromGroup(group_name: string): Object3D[] {
return this.coreObjectsFromGroup(group_name).map((co) => co.object());
}
coreObjectsFromGroup(group_name: string): CoreObject[] {
group_name = group_name.trim();
if (group_name !== '') {
const index = parseInt(group_name);
if (!CoreType.isNaN(index)) {
return ArrayUtils.compact([this.coreObjects()[index]]);
} else {
return this.coreObjects().filter((core_object) => {
return CoreString.matchMask(group_name, core_object.name());
});
}
} else {
return this.coreObjects();
}
}
boundingBox(): Box3 {
return (this._bounding_box = this._bounding_box || this._compute_bounding_box());
}
// bounding_sphere(): Sphere {
// return (this._bounding_sphere = this._bounding_sphere || this._compute_bounding_sphere());
// }
center(): Vector3 {
const center = new Vector3();
this.boundingBox().getCenter(center);
return center;
}
size(): Vector3 {
const size = new Vector3();
this.boundingBox().getSize(size);
return size;
}
private _compute_bounding_box() {
let bbox: Box3 | undefined; // = new Box3();
if (this._objects) {
for (let object of this._objects) {
const geometry = (object as Object3DWithGeometry).geometry;
if (geometry) {
geometry.computeBoundingBox();
if (bbox) {
bbox.expandByObject(object);
} else {
if (geometry.boundingBox) {
bbox = geometry.boundingBox.clone();
}
}
}
}
}
bbox = bbox || new Box3(new Vector3(-1, -1, -1), new Vector3(+1, +1, +1));
return bbox;
}
// private _compute_bounding_sphere() {
// let sphere: Sphere | undefined; // = new Box3();
// if (this._objects) {
// for (let object of this._objects) {
// const geometry = (object as Object3DWithGeometry).geometry;
// geometry.computeBoundingSphere();
// if (sphere) {
// sphere.expandByObject(object);
// } else {
// sphere = geometry.boundingBox.clone();
// }
// }
// }
// sphere = sphere || new Sphere(new Vector3(0, 0, 0), 1);
// return sphere;
// }
computeVertexNormals() {
for (let object of this.coreObjects()) {
object.computeVertexNormals();
}
}
hasAttrib(name: string) {
let first_geometry;
if ((first_geometry = this.coreGeometries()[0]) != null) {
return first_geometry.hasAttrib(name);
} else {
return false;
}
}
attribType(name: string) {
const first_core_geometry = this.coreGeometries()[0];
if (first_core_geometry != null) {
return first_core_geometry.attribType(name);
} else {
return null;
}
}
objectAttribType(name: string) {
const first_core_object = this.coreObjects()[0];
if (first_core_object != null) {
return first_core_object.attribType(name);
} else {
return null;
}
}
renameAttrib(old_name: string, new_name: string, attrib_class: AttribClass) {
switch (attrib_class) {
case CoreConstant.ATTRIB_CLASS.VERTEX:
if (this.hasAttrib(old_name)) {
if (this._objects) {
for (let object of this._objects) {
object.traverse((child) => {
const geometry = CoreGroup.geometryFromObject(child);
if (geometry) {
const core_geometry = new CoreGeometry(geometry);
core_geometry.renameAttrib(old_name, new_name);
}
});
}
}
}
break;
case CoreConstant.ATTRIB_CLASS.OBJECT:
if (this.hasAttrib(old_name)) {
if (this._objects) {
for (let object of this._objects) {
object.traverse((child) => {
const core_object = new CoreObject(child, 0);
core_object.renameAttrib(old_name, new_name);
});
}
}
}
break;
}
}
attribNames() {
let first_geometry;
if ((first_geometry = this.coreGeometries()[0]) != null) {
return first_geometry.attribNames();
} else {
return [];
}
}
objectAttribNames() {
let first_object;
if ((first_object = this.coreObjects()[0]) != null) {
return first_object.attribNames();
} else {
return [];
}
}
attribNamesMatchingMask(masks_string: GroupString) {
const masks = CoreString.attribNames(masks_string);
const matching_attrib_names: string[] = [];
for (let attrib_name of this.attribNames()) {
for (let mask of masks) {
if (CoreString.matchMask(attrib_name, mask)) {
matching_attrib_names.push(attrib_name);
}
}
}
return ArrayUtils.uniq(matching_attrib_names);
}
attribSizes() {
let first_geometry;
if ((first_geometry = this.coreGeometries()[0]) != null) {
return first_geometry.attribSizes();
} else {
return {};
}
}
objectAttribSizes(): PolyDictionary<AttribSize> {
let first_object;
if ((first_object = this.coreObjects()[0]) != null) {
return first_object.attribSizes();
} else {
return {};
}
}
attribSize(attrib_name: string) {
let first_geometry;
if ((first_geometry = this.coreGeometries()[0]) != null) {
return first_geometry.attribSize(attrib_name);
} else {
return 0;
}
}
addNumericVertexAttrib(name: string, size: number, default_value: NumericAttribValue) {
if (default_value == null) {
default_value = CoreAttribute.default_value(size);
}
for (let core_geometry of this.coreGeometries()) {
core_geometry.addNumericAttrib(name, size, default_value);
}
}
// add_numeric_object_attrib(name: string, size: number, default_value: NumericAttribValue) {
// if (default_value == null) {
// default_value = CoreAttribute.default_value(size);
// }
// for (let core_object of this.coreObjects()) {
// core_object.addNumericAttrib(name, default_value);
// }
// }
static clone(src_group: Group) {
const new_group = new Group();
src_group.children.forEach((src_object) => {
const new_object = CoreObject.clone(src_object);
new_group.add(new_object);
});
return new_group;
}
}