@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
257 lines (245 loc) • 8.17 kB
text/typescript
import {
BufferGeometry,
Object3D,
Mesh,
Vector3,
BufferAttribute,
Float32BufferAttribute,
Int32BufferAttribute,
InstancedBufferAttribute,
} from 'three';
import {CoreObjectType, ObjectContent} from '../../ObjectContent';
import {CorePoint} from '../../entities/point/CorePoint';
import {PointAttributesDict} from '../../entities/point/Common';
import {Attribute} from '../../Attribute';
import {objectCloneDeep} from '../../../ObjectUtils';
import {NumericAttribValue} from '../../../../types/GlobalTypes';
import {markedAsInstance} from '../../GeometryUtils';
import {pointsCountFromBufferGeometry, positionAttributeNameFromBufferGeometry} from './CoreThreejsPointUtils';
import {attributeNumericValues, AttributeNumericValuesOptions} from '../../entities/utils/Common';
import {ThreejsVertex} from './ThreejsVertex';
import {pointsCountFromObject} from '../../entities/point/CorePointUtils';
import {TraversedRelatedEntityData} from '../../entities/utils/TraversedRelatedEntities';
import {CoreEntityWithObject} from '../../CoreEntity';
const INDEX_ATTRIB_VALUES = 'indexedAttribValues';
const target: AttributeNumericValuesOptions = {
attributeAdded: false,
values: [],
};
export class ThreejsPoint extends CorePoint<CoreObjectType.THREEJS> {
protected _geometry?: BufferGeometry;
constructor(object: Object3D, index: number) {
super(object, index);
this._updateGeometry();
}
override setIndex(index: number, object?: Object3D) {
this._index = index;
if (object) {
this._object = object;
this._updateGeometry();
}
return this;
}
private _updateGeometry() {
const geometry = (this._object as Mesh).geometry as BufferGeometry | undefined;
if (geometry) {
this._geometry = geometry;
}
}
geometry() {
return this._geometry;
}
static override addAttribute(object: Object3D, attribName: string, attribute: BufferAttribute) {
const geometry = (object as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
geometry.setAttribute(attribName, attribute);
}
static override attributes<T extends CoreObjectType>(object: ObjectContent<T>): PointAttributesDict | undefined {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
return geometry.attributes;
}
static override entitiesCount<T extends CoreObjectType>(object: ObjectContent<T>) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return 0;
}
return pointsCountFromBufferGeometry(geometry);
}
static positionAttributeName<T extends CoreObjectType>(object: ObjectContent<T>) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return null;
}
return positionAttributeNameFromBufferGeometry(geometry);
}
static position<T extends CoreObjectType>(object: ObjectContent<T>, index: number, target: Vector3) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return null;
}
const {array} = geometry.getAttribute(Attribute.POSITION) as BufferAttribute;
return target.fromArray(array, index * 3);
}
override position(target: Vector3): Vector3 {
if (!this._geometry) {
return target;
}
const {array} = this._geometry.getAttribute(Attribute.POSITION) as BufferAttribute;
return target.fromArray(array, this._index * 3);
}
override normal(target: Vector3): Vector3 {
if (!this._geometry) {
return target;
}
const {array} = this._geometry.getAttribute(Attribute.NORMAL) as BufferAttribute;
return target.fromArray(array, this._index * 3);
}
static override computeNormals<T extends CoreObjectType>(object: ObjectContent<T>) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return null;
}
geometry.computeVertexNormals();
}
static override markAttribAsNeedsUpdate<T extends CoreObjectType>(object: ObjectContent<T>, attribName: string) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return null;
}
const attribute = geometry.getAttribute(attribName);
if (!attribute) {
return;
}
attribute.needsUpdate = true;
}
//
//
//
//
//
static override userDataAttribs<T extends CoreObjectType>(object: ObjectContent<T>) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return {};
}
return (geometry.userData[INDEX_ATTRIB_VALUES] = geometry.userData[INDEX_ATTRIB_VALUES] || {});
}
static override setIndexedAttribute<T extends CoreObjectType>(
object: ObjectContent<T>,
attribName: string,
values: string[],
indices: number[]
) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
this.setIndexedAttributeValues(object, attribName, values);
geometry.setAttribute(attribName, new Int32BufferAttribute(indices, 1));
geometry.getAttribute(attribName).needsUpdate = true;
}
static override attribValueIndex<T extends CoreObjectType>(
object: ObjectContent<T>,
index: number,
attribName: string
): number {
if (this.isAttribIndexed(object, attribName)) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (geometry) {
return (geometry.getAttribute(attribName) as BufferAttribute).array[index];
}
}
return -1;
}
//
//
//
//
//
static override renameAttribute<T extends CoreObjectType>(
object: ObjectContent<T>,
oldName: string,
newName: string
) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
if (this.isAttribIndexed(object, oldName)) {
this.userDataAttribs(object)[newName] = objectCloneDeep(this.userDataAttribs(object)[oldName]);
delete this.userDataAttribs(object)[oldName];
}
const oldAttrib = geometry.getAttribute(oldName) as BufferAttribute;
geometry.setAttribute(newName, new Float32BufferAttribute(oldAttrib.array, oldAttrib.itemSize));
return geometry.deleteAttribute(oldName);
}
static override deleteAttribute<T extends CoreObjectType>(object: ObjectContent<T>, attribName: string) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
if (this.isAttribIndexed(object, attribName)) {
delete this.userDataAttribs(object)[attribName];
}
return geometry.deleteAttribute(attribName);
}
static override addNumericAttribute<T extends CoreObjectType>(
object: ObjectContent<T>,
attribName: string,
size: number = 1,
defaultValue: NumericAttribValue = 0
) {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
attributeNumericValues(object, pointsCountFromObject, size, defaultValue, target);
if (target.attributeAdded) {
if (markedAsInstance(geometry)) {
const valuesAsTypedArray = new Float32Array(target.values);
geometry.setAttribute(attribName.trim(), new InstancedBufferAttribute(valuesAsTypedArray, size));
} else {
geometry.setAttribute(attribName.trim(), new Float32BufferAttribute(target.values, size));
}
} else {
console.warn(defaultValue);
throw `CoreThreejsPoint.addNumericAttrib error: no other default value allowed for now (default given: ${defaultValue})`;
}
}
//
//
// RELATED ENTITIES
//
//
static override relatedVertexIds<T extends CoreObjectType>(
object: ObjectContent<T>,
pointIndex: number,
target: number[],
traversedRelatedEntityData?: TraversedRelatedEntityData
): void {
const geometry = (object as any as Mesh).geometry as BufferGeometry | undefined;
if (!geometry) {
return;
}
const index = geometry.getIndex();
if (!index) {
return;
}
const indexArray = index.array;
let i = 0;
for (const indexValue of indexArray) {
if (indexValue == pointIndex) {
target.push(i);
}
i++;
}
}
static override relatedVertexClass<T extends CoreObjectType>(object: ObjectContent<T>) {
return ThreejsVertex as any as typeof CoreEntityWithObject<T>;
}
}