UNPKG

polygonjs-engine

Version:

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

242 lines (219 loc) 6.44 kB
import {AttribValue, ColorLike, NumericAttribValue, Vector2Like, Vector3Like} from '../../types/GlobalTypes'; import {Vector4} from 'three/src/math/Vector4'; import {Vector3} from 'three/src/math/Vector3'; import {Vector2} from 'three/src/math/Vector2'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {CoreAttribute} from './Attribute'; import {CoreGeometry} from './Geometry'; import {CoreEntity} from './Entity'; import {CoreType} from '../Type'; const ATTRIB_NAMES = { POSITION: 'position', NORMAL: 'normal', }; enum ComponentName { x = 'x', y = 'y', z = 'z', w = 'w', r = 'r', g = 'g', b = 'b', } const COMPONENT_INDICES = { x: 0, y: 1, z: 2, w: 3, r: 0, g: 1, b: 2, }; const PTNUM = 'ptnum'; const DOT = '.'; export class CorePoint extends CoreEntity { _geometry: BufferGeometry; _position: Vector3 | undefined; _normal: Vector3 | undefined; constructor(private _core_geometry: CoreGeometry, _index: number) { super(_index); this._geometry = this._core_geometry.geometry(); } core_geometry() { return this._core_geometry; } geometry() { return (this._geometry = this._geometry || this._core_geometry.geometry()); } attribSize(name: string): number { name = CoreAttribute.remap_name(name); return this._geometry.getAttribute(name).itemSize; } hasAttrib(name: string): boolean { const remapped_name = CoreAttribute.remap_name(name); return this._core_geometry.hasAttrib(remapped_name); } attribValue(name: string, target?: Vector2 | Vector3 | Vector4): AttribValue { if (name === PTNUM) { return this.index(); } else { let component_name = null; let component_index = null; if (name[name.length - 2] === DOT) { component_name = name[name.length - 1] as ComponentName; component_index = COMPONENT_INDICES[component_name]; name = name.substring(0, name.length - 2); } const remaped_name = CoreAttribute.remap_name(name); const attrib = this._geometry.getAttribute(remaped_name); if (attrib) { const {array} = attrib; if (this._core_geometry.isAttribIndexed(remaped_name)) { return this.indexedAttribValue(remaped_name); } else { const size = attrib.itemSize; const start_index = this._index * size; if (component_index == null) { switch (size) { case 1: return array[start_index]; break; case 2: target = target || new Vector2(); target.fromArray(array, start_index); return target; break; case 3: target = target || new Vector3(); target.fromArray(array, start_index); return target; break; case 4: target = target || new Vector4(); target.fromArray(array, start_index); return target; break; default: throw `size not valid (${size})`; } } else { switch (size) { case 1: return array[start_index]; break; default: return array[start_index + component_index]; } } } } else { const message = `attrib ${name} not found. availables are: ${Object.keys( this._geometry.attributes || {} ).join(',')}`; console.warn(message); throw message; } } } indexedAttribValue(name: string): string { const value_index = this.attribValueIndex(name); //attrib.value() return this._core_geometry.userDataAttrib(name)[value_index]; } stringAttribValue(name: string) { return this.indexedAttribValue(name); } attribValueIndex(name: string): number { if (this._core_geometry.isAttribIndexed(name)) { return this._geometry.getAttribute(name).array[this._index]; } else { return -1; } } isAttribIndexed(name: string) { return this._core_geometry.isAttribIndexed(name); } position(target?: Vector3): Vector3 { const {array} = this._geometry.getAttribute(ATTRIB_NAMES.POSITION); if (target) { return target.fromArray(array, this._index * 3); } else { this._position = this._position || new Vector3(); return this._position.fromArray(array, this._index * 3); } } setPosition(new_position: Vector3) { this.setAttribValueVector3(ATTRIB_NAMES.POSITION, new_position); } normal(): Vector3 { const {array} = this._geometry.getAttribute(ATTRIB_NAMES.NORMAL); this._normal = this._normal || new Vector3(); return this._normal.fromArray(array, this._index * 3); } setNormal(new_normal: Vector3) { return this.setAttribValueVector3(ATTRIB_NAMES.NORMAL, new_normal); } setAttribValue(name: string, value: NumericAttribValue | string) { // TODO: this fails if the value is null if (value == null) { return; } if (name == null) { throw 'Point.set_attrib_value requires a name'; } const attrib = this._geometry.getAttribute(name); const array = attrib.array as number[]; const attrib_size = attrib.itemSize; if (CoreType.isArray(value)) { for (let i = 0; i < attrib_size; i++) { array[this._index * attrib_size + i] = value[i]; } return; } switch (attrib_size) { case 1: array[this._index] = value as number; break; case 2: const v2 = value as Vector2Like; array[this._index * 2 + 0] = v2.x; array[this._index * 2 + 1] = v2.y; break; case 3: const is_color = (value as ColorLike).r != null; if (is_color) { const col = value as ColorLike; array[this._index * 3 + 0] = col.r; array[this._index * 3 + 1] = col.g; array[this._index * 3 + 2] = col.b; } else { const v3 = value as Vector3Like; array[this._index * 3 + 0] = v3.x; array[this._index * 3 + 1] = v3.y; array[this._index * 3 + 2] = v3.z; } break; default: console.warn(`Point.set_attrib_value does not yet allow attrib size ${attrib_size}`); throw `attrib size ${attrib_size} not implemented`; } } setAttribValueVector3(name: string, value: Vector3) { // TODO: this fails if the value is null if (value == null) { return; } if (name == null) { throw 'Point.set_attrib_value requires a name'; } const attrib = this._geometry.getAttribute(name); const array = attrib.array as number[]; const i = this._index * 3; array[i] = value.x; array[i + 1] = value.y; array[i + 2] = value.z; } setAttribIndex(name: string, new_value_index: number) { const array = this._geometry.getAttribute(name).array as number[]; return (array[this._index] = new_value_index); } }