UNPKG

polygonjs-engine

Version:

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

297 lines (296 loc) 9.64 kB
import {Vector3 as Vector32} from "three/src/math/Vector3"; import {Int32BufferAttribute} from "three/src/core/BufferAttribute"; import {Float32BufferAttribute} from "three/src/core/BufferAttribute"; import {CorePoint} from "./Point"; import {CoreFace} from "./Face"; import {ObjectType, AttribType} from "./Constant"; import {CoreAttribute} from "./Attribute"; import {CoreGeometryBuilderPoints} from "./builders/Points"; import {CoreGeometryBuilderMerge} from "./builders/Merge"; import {CoreGeometryBuilderMesh} from "./builders/Mesh"; import {CoreGeometryBuilderLineSegments} from "./builders/LineSegments"; import {TypeAssert} from "../../engine/poly/Assert"; import {CoreType} from "../Type"; import {ArrayUtils as ArrayUtils2} from "../ArrayUtils"; import {ObjectUtils as ObjectUtils2} from "../ObjectUtils"; const CoreGeometry2 = class { constructor(_geometry) { this._geometry = _geometry; } geometry() { return this._geometry; } uuid() { return this._geometry.uuid; } boundingBox() { return this._bounding_box = this._bounding_box || this._create_bounding_box(); } _create_bounding_box() { this._geometry.computeBoundingBox(); if (this._geometry.boundingBox) { return this._geometry.boundingBox; } } markAsInstance() { this._geometry.userData["is_instance"] = true; } static markedAsInstance(geometry) { return geometry.userData["is_instance"] === true; } markedAsInstance() { return CoreGeometry2.markedAsInstance(this._geometry); } positionAttribName() { let name = "position"; if (this.markedAsInstance()) { name = "instancePosition"; } return name; } computeVertexNormals() { this._geometry.computeVertexNormals(); } userDataAttribs() { const key = "indexed_attrib_values"; return this._geometry.userData[key] = this._geometry.userData[key] || {}; } indexedAttributeNames() { return Object.keys(this.userDataAttribs() || {}); } userDataAttrib(name) { name = CoreAttribute.remap_name(name); return this.userDataAttribs()[name]; } isAttribIndexed(name) { name = CoreAttribute.remap_name(name); return this.userDataAttrib(name) != null; } hasAttrib(name) { if (name === "ptnum") { return true; } name = CoreAttribute.remap_name(name); return this._geometry.attributes[name] != null; } attribType(name) { if (this.isAttribIndexed(name)) { return AttribType.STRING; } else { return AttribType.NUMERIC; } } attribNames() { return Object.keys(this._geometry.attributes); } attribSizes() { const h = {}; for (let attrib_name of this.attribNames()) { h[attrib_name] = this._geometry.attributes[attrib_name].itemSize; } return h; } attribSize(name) { let attrib; name = CoreAttribute.remap_name(name); if ((attrib = this._geometry.attributes[name]) != null) { return attrib.itemSize; } else { if (name === "ptnum") { return 1; } else { return 0; } } } setIndexedAttributeValues(name, values) { this.userDataAttribs()[name] = values; } setIndexedAttribute(name, values, indices) { this.setIndexedAttributeValues(name, values); this._geometry.setAttribute(name, new Int32BufferAttribute(indices, 1)); } addNumericAttrib(name, size = 1, default_value = 0) { const values = []; let attribute_added = false; if (CoreType.isNumber(default_value)) { for (let i = 0; i < this.pointsCount(); i++) { for (let j = 0; j < size; j++) { values.push(default_value); } } attribute_added = true; } else { if (size > 1) { if (CoreType.isArray(default_value)) { for (let i = 0; i < this.pointsCount(); i++) { for (let j = 0; j < size; j++) { values.push(default_value[j]); } } attribute_added = true; } else { const vec2 = default_value; if (size == 2 && vec2.x != null && vec2.y != null) { for (let i = 0; i < this.pointsCount(); i++) { values.push(vec2.x); values.push(vec2.y); } attribute_added = true; } const vec3 = default_value; if (size == 3 && vec3.x != null && vec3.y != null && vec3.z != null) { for (let i = 0; i < this.pointsCount(); i++) { values.push(vec3.x); values.push(vec3.y); values.push(vec3.z); } attribute_added = true; } const col = default_value; if (size == 3 && col.r != null && col.g != null && col.b != null) { for (let i = 0; i < this.pointsCount(); i++) { values.push(col.r); values.push(col.g); values.push(col.b); } attribute_added = true; } const vec4 = default_value; if (size == 4 && vec4.x != null && vec4.y != null && vec4.z != null && vec4.w != null) { for (let i = 0; i < this.pointsCount(); i++) { values.push(vec4.x); values.push(vec4.y); values.push(vec4.z); values.push(vec4.w); } attribute_added = true; } } } } if (attribute_added) { this._geometry.setAttribute(name.trim(), new Float32BufferAttribute(values, size)); } else { console.warn(default_value); throw `CoreGeometry.add_numeric_attrib error: no other default value allowed for now in add_numeric_attrib (default given: ${default_value})`; } } initPositionAttribute(points_count, default_value) { const values = []; if (default_value == null) { default_value = new Vector32(); } for (let i = 0; i < points_count; i++) { values.push(default_value.x); values.push(default_value.y); values.push(default_value.z); } return this._geometry.setAttribute("position", new Float32BufferAttribute(values, 3)); } addAttribute(name, attrib_data) { switch (attrib_data.type()) { case AttribType.STRING: return console.log("TODO: to implement"); case AttribType.NUMERIC: return this.addNumericAttrib(name, attrib_data.size()); } } renameAttrib(old_name, new_name) { if (this.isAttribIndexed(old_name)) { this.userDataAttribs()[new_name] = ObjectUtils2.clone(this.userDataAttribs()[old_name]); delete this.userDataAttribs()[old_name]; } const old_attrib = this._geometry.getAttribute(old_name); this._geometry.setAttribute(new_name.trim(), new Float32BufferAttribute(old_attrib.array, old_attrib.itemSize)); return this._geometry.deleteAttribute(old_name); } deleteAttribute(name) { if (this.isAttribIndexed(name)) { delete this.userDataAttribs()[name]; } return this._geometry.deleteAttribute(name); } clone() { return CoreGeometry2.clone(this._geometry); } static clone(src_geometry) { let src_userData; const new_geometry = src_geometry.clone(); if ((src_userData = src_geometry.userData) != null) { new_geometry.userData = ObjectUtils2.cloneDeep(src_userData); } return new_geometry; } pointsCount() { return CoreGeometry2.pointsCount(this._geometry); } static pointsCount(geometry) { let position; let count = 0; const core_geometry = new this(geometry); let position_attrib_name = "position"; if (core_geometry.markedAsInstance()) { position_attrib_name = "instancePosition"; } if ((position = geometry.getAttribute(position_attrib_name)) != null) { let array; if ((array = position.array) != null) { count = array.length / 3; } } return count; } points() { return this._points = this._points || this.pointsFromGeometry(); } resetPoints() { this._points = void 0; } pointsFromGeometry() { const points = []; const position_attrib = this._geometry.getAttribute(this.positionAttribName()); if (position_attrib != null) { const points_count = position_attrib.array.length / 3; for (let point_index = 0; point_index < points_count; point_index++) { const point = new CorePoint(this, point_index); points.push(point); } } return points; } static geometryFromPoints(points, object_type) { switch (object_type) { case ObjectType.MESH: return this._mesh_builder.from_points(points); case ObjectType.POINTS: return this._points_builder.from_points(points); case ObjectType.LINE_SEGMENTS: return this._lines_segment_builder.from_points(points); case ObjectType.OBJECT3D: return null; case ObjectType.LOD: return null; } TypeAssert.unreachable(object_type); } static merge_geometries(geometries) { return CoreGeometryBuilderMerge.merge(geometries); } segments() { const index = this.geometry().index?.array || []; return ArrayUtils2.chunk(index, 2); } faces() { return this.facesFromGeometry(); } facesFromGeometry() { const index_array = this.geometry().index?.array || []; const faces_count = index_array.length / 3; return ArrayUtils2.range(faces_count).map((i) => new CoreFace(this, i)); } }; export let CoreGeometry = CoreGeometry2; CoreGeometry._mesh_builder = new CoreGeometryBuilderMesh(); CoreGeometry._points_builder = new CoreGeometryBuilderPoints(); CoreGeometry._lines_segment_builder = new CoreGeometryBuilderLineSegments();