{"version":3,"file":"Geometry.mjs","sources":["../../../../../src/rendering/renderers/shared/geometry/Geometry.ts"],"sourcesContent":["import EventEmitter from 'eventemitter3';\nimport { Bounds } from '../../../../scene/container/bounds/Bounds';\nimport { uid } from '../../../../utils/data/uid';\nimport { type GlGeometryGpuData } from '../../gl/geometry/GlGeometrySystem';\nimport { type GPUDataOwner } from '../../types';\nimport { Buffer } from '../buffer/Buffer';\nimport { type GCable, type GCData } from '../GCSystem';\nimport { ensureIsBuffer } from './utils/ensureIsBuffer';\nimport { getGeometryBounds } from './utils/getGeometryBounds';\n\nimport type { TypedArray } from '../buffer/Buffer';\nimport type { Topology, VertexFormat } from './const';\n\n/**\n * The index buffer array type used in geometries.\n * @category rendering\n * @advanced\n */\nexport type IndexBufferArray = Uint16Array | Uint32Array;\n\n/**\n * The attribute data for a geometries attributes\n * @category rendering\n * @advanced\n */\nexport interface Attribute\n{\n    /** the buffer that this attributes data belongs to */\n    buffer: Buffer;\n    /** the format of the attribute */\n    format?: VertexFormat;\n    /** the stride of the data in the buffer - in bytes*/\n    stride?: number;\n    /** the offset of the attribute from the buffer, defaults to 0 - in bytes*/\n    offset?: number;\n    /** is this an instanced buffer? (defaults to false) */\n    instance?: boolean;\n    /** the number of elements to be rendered. If not specified, all vertices after the starting vertex will be drawn. */\n    size?: number;\n    /**\n     * the starting vertex in the geometry to start drawing from. If not specified,\n     *  drawing will start from the first vertex.\n     */\n    start?: number;\n    /**\n     * attribute divisor for instanced rendering. Note: this is a **WebGL-only** feature, the WebGPU renderer will\n     * issue a warning if one of the attributes has divisor set.\n     */\n    divisor?: number;\n}\n\n/**\n * The attribute option used by the constructor for adding geometries attributes\n * extends {@link Attribute} but allows for the buffer to be a typed or number array\n * @category rendering\n * @advanced\n */\nexport type AttributeOption = Omit<Attribute, 'buffer'> & { buffer: Buffer | TypedArray | number[]}\n| Buffer | TypedArray | number[];\n\n/**\n * The attribute options used by the constructor for adding geometries attributes\n * extends {@link Attribute} but allows for the buffer to be a typed or number array\n * @category rendering\n * @advanced\n */\nexport type AttributeOptions = Record<string, AttributeOption>;\n\n/**\n * the interface that describes the structure of the geometry\n * @category rendering\n * @advanced\n */\nexport interface GeometryDescriptor\n{\n    /** an optional label to easily identify the geometry */\n    label?: string;\n    /** the attributes that make up the geometry */\n    attributes?: AttributeOptions;\n    /** optional index buffer for this geometry */\n    indexBuffer?: Buffer | TypedArray | number[];\n    /** the topology of the geometry, defaults to 'triangle-list' */\n    topology?: Topology;\n\n    instanceCount?: number;\n}\nfunction ensureIsAttribute(attribute: AttributeOption): Attribute\n{\n    if (attribute instanceof Buffer || Array.isArray(attribute) || (attribute as TypedArray).BYTES_PER_ELEMENT)\n    {\n        attribute = {\n            buffer: attribute as Buffer | TypedArray | number[],\n        };\n    }\n\n    (attribute as Attribute).buffer = ensureIsBuffer(attribute.buffer as Buffer | TypedArray | number[], false);\n\n    return attribute as Attribute;\n}\n\n/**\n * A Geometry is a low-level object that represents the structure of 2D shapes in terms of vertices and attributes.\n * It's a crucial component for rendering as it describes the shape and format of the data that will go through the shaders.\n * Essentially, a Geometry object holds the data you'd send to a GPU buffer.\n *\n * A geometry is basically made of two components:\n * <br>\n * <b>Attributes</b>: These are essentially arrays that define properties of the vertices like position, color,\n * texture coordinates, etc. They map directly to attributes in your vertex shaders.\n * <br>\n * <b>Indices</b>: An optional array that describes how the vertices are connected.\n * If not provided, vertices will be interpreted in the sequence they're given.\n * @example\n *\n * const geometry = new Geometry({\n *   attributes: {\n *     aPosition: [ // add some positions\n *       0, 0,\n *       0, 100,\n *       100, 100,\n *       100,   0,\n *     ],\n *     aUv: [ // add some uvs\n *       0, 0,\n *       0, 1,\n *       1, 1,\n *       1, 0,\n *     ]\n *   }\n * });\n * @category rendering\n * @advanced\n */\nexport class Geometry extends EventEmitter<{\n    update: Geometry,\n    destroy: Geometry,\n    unload: Geometry,\n}> implements GPUDataOwner, GCable\n{\n    /** @internal */\n    public _gpuData: Record<number, GlGeometryGpuData> = Object.create(null);\n    /** @internal */\n    public _gcData?: GCData;\n    /** If set to true, the resource will be garbage collected automatically when it is not used. */\n    public autoGarbageCollect = true;\n    /** @internal */\n    public _gcLastUsed = -1;\n\n    /** The topology of the geometry. */\n    public topology: Topology;\n    /** The unique id of the geometry. */\n    public readonly uid: number = uid('geometry');\n    /** A record of the attributes of the geometry. */\n    public readonly attributes: Record<string, Attribute>;\n    /** The buffers that the attributes use */\n    public readonly buffers: Buffer[];\n    /** The index buffer of the geometry */\n    public indexBuffer: Buffer;\n\n    /**\n     * the layout key will be generated by WebGPU all geometries that have the same structure\n     * will have the same layout key. This is used to cache the pipeline layout\n     * @internal\n     */\n    public _layoutKey = 0;\n\n    /** the instance count of the geometry to draw */\n    public instanceCount = 1;\n\n    private readonly _bounds: Bounds = new Bounds();\n    private _boundsDirty = true;\n\n    /**\n     * Create a new instance of a geometry\n     * @param options - The options for the geometry.\n     */\n    constructor(options: GeometryDescriptor = {})\n    {\n        super();\n\n        const { attributes, indexBuffer, topology } = options;\n\n        this.buffers = [];\n\n        this.attributes = {};\n\n        if (attributes)\n        {\n            for (const i in attributes)\n            {\n                this.addAttribute(i, attributes[i]);\n            }\n        }\n\n        this.instanceCount = options.instanceCount ?? 1;\n\n        if (indexBuffer)\n        {\n            this.addIndex(indexBuffer);\n        }\n\n        this.topology = topology || 'triangle-list';\n    }\n\n    protected onBufferUpdate(): void\n    {\n        this._boundsDirty = true;\n        this.emit('update', this);\n    }\n\n    /**\n     * Returns the requested attribute.\n     * @param id - The name of the attribute required\n     * @returns - The attribute requested.\n     */\n    public getAttribute(id: string): Attribute\n    {\n        return this.attributes[id];\n    }\n\n    /**\n     * Returns the index buffer\n     * @returns - The index buffer.\n     */\n    public getIndex(): Buffer\n    {\n        return this.indexBuffer;\n    }\n\n    /**\n     * Returns the requested buffer.\n     * @param id - The name of the buffer required.\n     * @returns - The buffer requested.\n     */\n    public getBuffer(id: string): Buffer\n    {\n        return this.getAttribute(id).buffer;\n    }\n\n    /**\n     * Used to figure out how many vertices there are in this geometry\n     * @returns the number of vertices in the geometry\n     */\n    public getSize(): number\n    {\n        for (const i in this.attributes)\n        {\n            const attribute = this.attributes[i];\n            const buffer = attribute.buffer;\n\n            // TODO use SIZE again like v7..\n            return (buffer.data as any).length / ((attribute.stride / 4) || attribute.size);\n        }\n\n        return 0;\n    }\n\n    /**\n     * Adds an attribute to the geometry.\n     * @param name - The name of the attribute to add.\n     * @param attributeOption - The attribute option to add.\n     */\n    public addAttribute(name: string, attributeOption: AttributeOption): void\n    {\n        const attribute = ensureIsAttribute(attributeOption);\n\n        const bufferIndex = this.buffers.indexOf(attribute.buffer);\n\n        if (bufferIndex === -1)\n        {\n            this.buffers.push(attribute.buffer);\n\n            // two events here - one for a resize (new buffer change)\n            // and one for an update (existing buffer change)\n            attribute.buffer.on('update', this.onBufferUpdate, this);\n            attribute.buffer.on('change', this.onBufferUpdate, this);\n        }\n        this.attributes[name] = attribute;\n    }\n\n    /**\n     * Adds an index buffer to the geometry.\n     * @param indexBuffer - The index buffer to add. Can be a Buffer, TypedArray, or an array of numbers.\n     */\n    public addIndex(indexBuffer: Buffer | TypedArray | number[]): void\n    {\n        this.indexBuffer = ensureIsBuffer(indexBuffer, true);\n        this.buffers.push(this.indexBuffer);\n    }\n\n    /** Returns the bounds of the geometry. */\n    get bounds(): Bounds\n    {\n        if (!this._boundsDirty) return this._bounds;\n\n        this._boundsDirty = false;\n\n        return getGeometryBounds(this, 'aPosition', this._bounds);\n    }\n\n    /** Unloads the geometry from the GPU. */\n    public unload(): void\n    {\n        /** Unloads the GPU data from the view container. */\n        this.emit('unload', this);\n        for (const key in this._gpuData)\n        {\n            this._gpuData[key]?.destroy();\n        }\n        this._gpuData = Object.create(null);\n    }\n\n    /**\n     * destroys the geometry.\n     * @param destroyBuffers - destroy the buffers associated with this geometry\n     */\n    public destroy(destroyBuffers = false): void\n    {\n        this.emit('destroy', this);\n\n        this.removeAllListeners();\n\n        if (destroyBuffers)\n        {\n            this.buffers.forEach((buffer) => buffer.destroy());\n        }\n\n        this.unload();\n\n        this.indexBuffer?.destroy();\n        (this.attributes as null) = null;\n        (this.buffers as null) = null;\n        (this.indexBuffer as null) = null;\n        (this._bounds as null) = null;\n    }\n}\n"],"names":[],"mappings":"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"}