Files
Foundry-VTT-Docker/resources/app/client/pixi/groups/hidden.js
2025-01-04 00:34:03 +01:00

117 lines
3.2 KiB
JavaScript

/**
* A specialized canvas group for rendering hidden containers before all others (like masks).
* @extends {PIXI.Container}
*/
class HiddenCanvasGroup extends CanvasGroupMixin(PIXI.Container) {
constructor() {
super();
this.eventMode = "none";
this.#createMasks();
}
/**
* The container which hold masks.
* @type {PIXI.Container}
*/
masks = new PIXI.Container();
/** @override */
static groupName = "hidden";
/* -------------------------------------------- */
/**
* Add a mask to this group.
* @param {string} name Name of the mask.
* @param {PIXI.DisplayObject} displayObject Display object to add.
* @param {number|undefined} [position=undefined] Position of the mask.
*/
addMask(name, displayObject, position) {
if ( !((typeof name === "string") && (name.length > 0)) ) {
throw new Error(`Adding mask failed. Name ${name} is invalid.`);
}
if ( !displayObject.clear ) {
throw new Error("A mask container must implement a clear method.");
}
// Add the mask to the dedicated `masks` container
this.masks[name] = position
? this.masks.addChildAt(displayObject, position)
: this.masks.addChild(displayObject);
}
/* -------------------------------------------- */
/**
* Invalidate the masks: flag them for rerendering.
*/
invalidateMasks() {
for ( const mask of this.masks.children ) {
if ( !(mask instanceof CachedContainer) ) continue;
mask.renderDirty = true;
}
}
/* -------------------------------------------- */
/* Rendering */
/* -------------------------------------------- */
/** @inheritDoc */
async _draw(options) {
this.invalidateMasks();
this.addChild(this.masks);
await this.#drawMasks();
await super._draw(options);
}
/* -------------------------------------------- */
/**
* Perform necessary draw operations.
*/
async #drawMasks() {
await this.masks.vision.draw();
}
/* -------------------------------------------- */
/**
* Attach masks container to this canvas layer and create tile occlusion, vision masks and depth mask.
*/
#createMasks() {
// The canvas scissor mask is the first thing to render
const canvas = new PIXI.LegacyGraphics();
this.addMask("canvas", canvas);
// The scene scissor mask
const scene = new PIXI.LegacyGraphics();
this.addMask("scene", scene);
// Then we need to render vision mask
const vision = new CanvasVisionMask();
this.addMask("vision", vision);
// Then we need to render occlusion mask
const occlusion = new CanvasOcclusionMask();
this.addMask("occlusion", occlusion);
// Then the depth mask, which need occlusion
const depth = new CanvasDepthMask();
this.addMask("depth", depth);
}
/* -------------------------------------------- */
/* Tear-Down */
/* -------------------------------------------- */
/** @inheritDoc */
async _tearDown(options) {
this.removeChild(this.masks);
// Clear all masks (children of masks)
this.masks.children.forEach(c => c.clear());
// Then proceed normally
await super._tearDown(options);
}
}