import { GraphNode } from './graph_node.js';
import { Matrix4x4 } from '@zephyr3d/base';
import '../values.js';
import { InstanceBindGroupAllocator, RenderQueue } from '../render/render_queue.js';
import '../render/primitive.js';
import '@zephyr3d/device';
import '../material/shader/helper.js';
import '../material/lambert.js';
import '../material/blinn.js';
import '../material/unlit.js';
import '../material/particle.js';
import '../material/meshmaterial.js';
import '../material/grassmaterial.js';
import '../material/terrain-cm.js';
import '../material/pbrmr.js';
import '../material/pbrsg.js';
import '../material/pbrblueprint.js';
import '../material/sprite.js';
import '../material/sprite_std.js';
import '../utility/blueprint/material/texture.js';
import '../render/rendergraph/forward_plus_builder.js';
import '../render/sky.js';
import '../render/clipmap.js';
import '../shaders/atmosphere.js';
import { BoundingBox } from '../utility/bounding_volume.js';

const tmpMatrix = new Matrix4x4();
/**
 * Batch group node
 * @public
 */ class BatchGroup extends GraphNode {
    _renderQueueMap;
    _bindGroupAllocator;
    _changeTag;
    _staticBV;
    /**
   * Creates an instance of mesh node
   * @param scene - The scene to which the mesh node belongs
   */ constructor(scene){
        super(scene);
        this._renderQueueMap = new Map();
        this._changeTag = 0;
        this._bindGroupAllocator = new InstanceBindGroupAllocator();
        this._staticBV = false;
        const bvCallback = (function() {
            if (!this._staticBV) {
                this.invalidateBoundingVolume();
            }
        }).bind(this);
        this.on('visiblechanged', (node)=>{
            node.iterate((child)=>{
                if (child.isMesh()) {
                    this._changeTag++;
                    return true;
                }
                return false;
            });
        });
        this.on('nodeattached', (node)=>{
            node.iterate((child)=>{
                if (child.isMesh()) {
                    child.placeToOctree = false;
                    if (!this._staticBV) {
                        this.invalidateBoundingVolume();
                    }
                    child.on('bvchanged', bvCallback);
                    this._changeTag++;
                }
            });
        });
        this.on('noderemoved', (node)=>{
            node.iterate((child)=>{
                if (child.isMesh()) {
                    child.placeToOctree = true;
                    if (!this._staticBV) {
                        this.invalidateBoundingVolume();
                    }
                    child.off('bvchanged', bvCallback);
                    this._changeTag++;
                }
            });
        });
    }
    /**
   * {@inheritDoc Drawable.getName}
   */ getName() {
        return this._name;
    }
    /**
   * {@inheritDoc SceneNode.isBatchGroup}
   */ isBatchGroup() {
        return true;
    }
    /**
   * Force the batch state to be rebuilt
   */ invalidate() {
        this._changeTag++;
    }
    /** @internal */ _onDetached() {
        super._onDetached();
        // Usually the node will be garbage collected after it is detached,
        // We should reset the render queue to release the render bundles.
        this._renderQueueMap.forEach((val)=>{
            val.queue.reset();
        });
        this.invalidate();
    }
    /** @internal */ _onAttached() {
        // Reset the render queue when attached to a new scene.
        this.invalidate();
    }
    /** @internal */ computeBoundingVolume() {
        const bv = new BoundingBox();
        const invWorldMatrix = Matrix4x4.invertAffine(this.worldMatrix);
        bv.beginExtend();
        this.iterate((node)=>{
            if (node.isMesh()) {
                Matrix4x4.multiplyAffine(invWorldMatrix, node.worldMatrix, tmpMatrix);
                const wb = node.getBoundingVolume().transform(tmpMatrix).toAABB();
                bv.extend(wb.minPoint);
                bv.extend(wb.maxPoint);
            }
        });
        return bv.isValid() ? bv : null;
    }
    /** @internal */ setBoundingVolume(bv) {
        this._staticBV = !!bv;
        super.setBoundingVolume(bv);
    }
    /** @internal */ cull(cullVisitor) {
        let queueInfo = this._renderQueueMap.get(cullVisitor.renderPass);
        if (!queueInfo) {
            queueInfo = {
                queue: new RenderQueue(cullVisitor.renderPass, this._bindGroupAllocator),
                tag: -1
            };
            this._renderQueueMap.set(cullVisitor.renderPass, queueInfo);
        }
        if (queueInfo.tag !== this._changeTag) {
            queueInfo.tag = this._changeTag;
            queueInfo.queue.reset();
            const frustumCulling = cullVisitor.frustumCulling;
            const renderQueue = cullVisitor.renderQueue;
            cullVisitor.frustumCulling = false;
            cullVisitor.renderQueue = queueInfo.queue;
            this.iterate((node)=>{
                if (node.isMesh()) {
                    cullVisitor.visit(node);
                }
            });
            queueInfo.queue.end(cullVisitor.camera, true);
            cullVisitor.frustumCulling = frustumCulling;
            cullVisitor.renderQueue = renderQueue;
        }
        cullVisitor.pushRenderQueue(queueInfo.queue);
    }
}

export { BatchGroup };
//# sourceMappingURL=batchgroup.js.map
