|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import {
- BufferAttribute,
- BufferGeometry,
- BufferGeometry2,
- Class,
- Float32BufferAttribute,
- generateUiConfig,
- getOrCall,
- IGeometry,
- UiObjectConfig,
- } from 'threepipe'
-
- declare module 'threepipe'{
- interface IGeometryUserData{
- generationParams?: {
- type: string
- // [key: string]: any
- }
- }
- }
- export interface GeometryGenerator<T=any>{
- generate(g?: IGeometry, parameters?: T): IGeometry
- createUiConfig?(geometry: IGeometry): UiObjectConfig[]
- }
-
- function updateAttribute<T extends BufferAttribute=Float32BufferAttribute>(geometry: BufferGeometry, attribute: string, itemSize: number, array: any[], cls?: Class<T>) {
- const attr = geometry.getAttribute(attribute) as T
- const count = array.length / itemSize
- if (attr && attr.count === count) {
- attr.set(array)
- attr.needsUpdate = true
- } else {
- geometry.setAttribute(attribute, new (cls ?? Float32BufferAttribute)(array, itemSize))
- }
- return attr
- }
-
- function updateIndices(geometry: BufferGeometry, indices: any[]) {
- const index = geometry.index
- if (index && index.count === indices.length) {
- index.set(indices)
- index.needsUpdate = true // todo: wireframe attribute is not updating
- } else geometry.setIndex(indices)
- }
-
- export function updateUi(geometry: BufferGeometry, childrenUi: () => UiObjectConfig[]) {
- if (!(geometry as any).uiConfig) return
- let oldUi = (geometry as any).uiConfig?.children?.find((c: UiObjectConfig) => c.tags?.includes('generatedGeometry'))
- if (!oldUi) {
- oldUi = {
- type: 'folder',
- label: 'Generation Params',
- tags: ['generatedGeometry'],
- children: [],
- }
- ;(geometry as any).uiConfig.children?.push(oldUi)
- }
- if (geometry.userData.__generationParamsUiType !== geometry.userData.generationParams.type) {
- oldUi.children = childrenUi()
- geometry.userData.__generationParamsUiType = geometry.userData.generationParams.type
- oldUi.uiRefresh?.('postFrame', true)
- }
- }
-
- export abstract class AGeometryGenerator<Tp=any> implements GeometryGenerator<Tp> {
- constructor(public type: string) {
- }
-
- abstract defaultParams: Tp
-
- createUiConfig(geometry: IGeometry): UiObjectConfig[] {
- if (!geometry.userData.generationParams) return []
- const ui = generateUiConfig(geometry.userData.generationParams)
- // @ts-expect-error we assume only functions will be generated since its an object
- .map(v=>v())
- .filter(v=>getOrCall(v.property)?.[1] !== 'type')
- ui.forEach(u=> {
- u.onChange = () => this.generate(geometry)
- })
- return ui
- }
- protected abstract _generateData(params: Tp): {indices: number[]; vertices: number[]; normals: number[]; uvs: number[], groups?: {start: number, count: number, materialIndex: number}[]}
-
- generate(g?: IGeometry, parameters: Partial<Tp> = {}): IGeometry|BufferGeometry2 {
- const geometry: IGeometry = g ?? new BufferGeometry2()
- if (!geometry.userData.generationParams) geometry.userData.generationParams = {type: this.type}
- geometry.userData.generationParams.type = this.type
- if ((parameters as any).type) {
- console.error('Cannot change type of generated geometry here, use the plugin instead')
- return geometry
- }
- const params = {
- ...this.defaultParams,
- ...geometry.userData.generationParams,
- ...parameters,
- } as Tp
-
- const {indices, vertices, normals, uvs, groups} = this._generateData(params)
-
- // console.log(indices, vertices, normals, uvs, groups)
- updateIndices(geometry, indices)
- updateAttribute(geometry, 'position', 3, vertices)
- updateAttribute(geometry, 'normal', 3, normals)
- updateAttribute(geometry, 'uv', 2, uvs)
-
- if (groups) {
- geometry.clearGroups()
- for (const group of groups) {
- geometry.addGroup(group.start, group.count, group.materialIndex)
- }
- }
-
- geometry.computeBoundingBox()
- geometry.computeBoundingSphere()
-
- Object.assign(geometry.userData.generationParams, params)
-
- const childrenUi = ()=>this.createUiConfig(geometry)
- updateUi(geometry, childrenUi)
-
- geometry.setDirty()
- return geometry
- }
-
- }
|