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