import { type InstructionSet } from '../../rendering/renderers/shared/instructions/InstructionSet';
import { type RenderPipe } from '../../rendering/renderers/shared/instructions/RenderPipe';
import { type Renderer } from '../../rendering/renderers/types';
import { Bounds } from '../container/bounds/Bounds';
import { Container } from '../container/Container';
import { type IRenderLayer } from '../layers/RenderLayer';
import type { PointData } from '../../maths/point/PointData';
import type { View } from '../../rendering/renderers/shared/view/View';
import type { DestroyOptions } from '../container/destroyTypes';
/**
* A ViewContainer is a type of container that represents a view.
* This view can be a Sprite, a Graphics object, or any other object that can be rendered.
* This class is abstract and should not be used directly.
* @memberof scene
*/
export abstract class ViewContainer extends Container implements View
{
/** @private */
public override readonly renderPipeId: string;
/** @private */
public readonly canBundle = true;
/** @private */
public override allowChildren = false;
/** @private */
public _roundPixels: 0 | 1 = 0;
/** @private */
public _lastUsed = -1;
protected _bounds: Bounds = new Bounds(0, 1, 0, 0);
protected _boundsDirty = true;
/**
* The local bounds of the view.
* @type {rendering.Bounds}
*/
public get bounds()
{
if (!this._boundsDirty) return this._bounds;
this.updateBounds();
this._boundsDirty = false;
return this._bounds;
}
/** @private */
protected abstract updateBounds(): void;
/**
* Whether or not to round the x/y position of the sprite.
* @type {boolean}
*/
get roundPixels()
{
return !!this._roundPixels;
}
set roundPixels(value: boolean)
{
this._roundPixels = value ? 1 : 0;
}
/**
* Checks if the object contains the given point.
* @param point - The point to check
*/
public containsPoint(point: PointData)
{
const bounds = this.bounds;
const { x, y } = point;
return (x >= bounds.minX
&& x <= bounds.maxX
&& y >= bounds.minY
&& y <= bounds.maxY);
}
/** @private */
public abstract batched: boolean;
/** @private */
protected onViewUpdate()
{
this._didViewChangeTick++;
this._boundsDirty = true;
if (this.didViewUpdate) return;
this.didViewUpdate = true;
const renderGroup = this.renderGroup || this.parentRenderGroup;
if (renderGroup)
{
renderGroup.onChildViewUpdate(this);
}
}
public override destroy(options?: DestroyOptions): void
{
super.destroy(options);
this._bounds = null;
}
public override collectRenderablesSimple(
instructionSet: InstructionSet,
renderer: Renderer,
currentLayer: IRenderLayer,
): void
{
const { renderPipes, renderableGC } = renderer;
// TODO add blends in
renderPipes.blendMode.setBlendMode(this, this.groupBlendMode, instructionSet);
const rp = renderPipes as unknown as Record<string, RenderPipe>;
rp[this.renderPipeId].addRenderable(this, instructionSet);
renderableGC.addRenderable(this);
this.didViewUpdate = false;
const children = this.children;
const length = children.length;
for (let i = 0; i < length; i++)
{
children[i].collectRenderables(instructionSet, renderer, currentLayer);
}
}
}