UNPKG

polygonjs-engine

Version:

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

129 lines (119 loc) 4.7 kB
import {BaseSopOperation} from './_Base'; import {DefaultOperationParams} from '../_Base'; import {CoreGroup} from '../../../core/geometry/Group'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {BufferAttribute, Float32BufferAttribute} from 'three/src/core/BufferAttribute'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; interface AttribCopySopParams extends DefaultOperationParams { name: string; tnewName: boolean; newName: string; srcOffset: number; destOffset: number; } export class AttribCopySopOperation extends BaseSopOperation { static readonly DEFAULT_PARAMS: AttribCopySopParams = { name: '', tnewName: false, newName: '', srcOffset: 0, destOffset: 0, }; static readonly INPUT_CLONED_STATE = [InputCloneMode.FROM_NODE, InputCloneMode.NEVER]; static type(): Readonly<'attribCopy'> { return 'attribCopy'; } cook(input_contents: CoreGroup[], params: AttribCopySopParams) { const core_group_dest = input_contents[0]; const core_group_src = input_contents[1] || core_group_dest; const attrib_names = core_group_src.attribNamesMatchingMask(params.name); for (let attrib_name of attrib_names) { this.copy_vertex_attribute_between_core_groups(core_group_dest, core_group_src, attrib_name, params); } return core_group_dest; } private copy_vertex_attribute_between_core_groups( core_group_dest: CoreGroup, core_group_src: CoreGroup, attrib_name: string, params: AttribCopySopParams ) { const src_objects = core_group_src.objectsWithGeo(); const dest_objects = core_group_dest.objectsWithGeo(); if (dest_objects.length > src_objects.length) { this.states?.error.set('second input does not have enough objects to copy attributes from'); } else { for (let i = 0; i < dest_objects.length; i++) { const dest_geometry = dest_objects[i].geometry; const src_geometry = dest_objects[i].geometry; this.copy_vertex_attribute_between_geometries(dest_geometry, src_geometry, attrib_name, params); } } } private copy_vertex_attribute_between_geometries( dest_geometry: BufferGeometry, src_geometry: BufferGeometry, attrib_name: string, params: AttribCopySopParams ) { const src_attrib = src_geometry.getAttribute(attrib_name); if (src_attrib) { const size = src_attrib.itemSize; const src_points_count = src_geometry.getAttribute('position').array.length / 3; const dest_points_count = dest_geometry.getAttribute('position').array.length / 3; if (dest_points_count > src_points_count) { this.states?.error.set('not enough points in second input'); } const dest_name = params.tnewName ? params.newName : attrib_name; let dest_attribute = dest_geometry.getAttribute(dest_name); if (dest_attribute) { this._fill_dest_array(dest_attribute as BufferAttribute, src_attrib as BufferAttribute, params); (dest_attribute as BufferAttribute).needsUpdate = true; } else { const src_array = src_attrib.array as number[]; const dest_array = src_array.slice(0, dest_points_count * size); dest_geometry.setAttribute(dest_name, new Float32BufferAttribute(dest_array, size)); } } else { this.states?.error.set(`attribute '${attrib_name}' does not exist on second input`); } } private _fill_dest_array( dest_attribute: BufferAttribute, src_attribute: BufferAttribute, params: AttribCopySopParams ) { const dest_array = dest_attribute.array as number[]; const src_array = src_attribute.array as number[]; const dest_array_size = dest_array.length; const dest_item_size = dest_attribute.itemSize; const src_item_size = src_attribute.itemSize; const srcOffset = params.srcOffset; const destOffset = params.destOffset; // if same itemSize, we copy item by item if (dest_attribute.itemSize == src_attribute.itemSize) { dest_attribute.copyArray(src_attribute.array); for (let i = 0; i < dest_array_size; i++) { dest_array[i] = src_array[i]; } } else { const points_count = dest_array.length / dest_item_size; if (dest_item_size < src_item_size) { // if dest attrib is smaller than src attrib (ie: vector -> to float) // we copy only the selected items from src for (let i = 0; i < points_count; i++) { for (let j = 0; j < dest_item_size; j++) { dest_array[i * dest_item_size + j + destOffset] = src_array[i * src_item_size + j + srcOffset]; } } } else { // if dest attrib is larger than src attrib (ie: float -> vector ) for (let i = 0; i < points_count; i++) { for (let j = 0; j < src_item_size; j++) { dest_array[i * dest_item_size + j + destOffset] = src_array[i * src_item_size + j + srcOffset]; } } } } } }