Initial
This commit is contained in:
613
resources/app/client/pixi/groups/primary.js
Normal file
613
resources/app/client/pixi/groups/primary.js
Normal file
@@ -0,0 +1,613 @@
|
||||
/**
|
||||
* The primary Canvas group which generally contains tangible physical objects which exist within the Scene.
|
||||
* This group is a {@link CachedContainer} which is rendered to the Scene as a {@link SpriteMesh}.
|
||||
* This allows the rendered result of the Primary Canvas Group to be affected by a {@link BaseSamplerShader}.
|
||||
* @extends {CachedContainer}
|
||||
* @mixes CanvasGroupMixin
|
||||
* @category - Canvas
|
||||
*/
|
||||
class PrimaryCanvasGroup extends CanvasGroupMixin(CachedContainer) {
|
||||
constructor(sprite) {
|
||||
sprite ||= new SpriteMesh(undefined, BaseSamplerShader);
|
||||
super(sprite);
|
||||
this.eventMode = "none";
|
||||
this.#createAmbienceFilter();
|
||||
this.on("childAdded", this.#onChildAdded);
|
||||
this.on("childRemoved", this.#onChildRemoved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort order to break ties on the group/layer level.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SORT_LAYERS = Object.freeze({
|
||||
SCENE: 0,
|
||||
TILES: 500,
|
||||
DRAWINGS: 600,
|
||||
TOKENS: 700,
|
||||
WEATHER: 1000
|
||||
});
|
||||
|
||||
/** @override */
|
||||
static groupName = "primary";
|
||||
|
||||
/** @override */
|
||||
static textureConfiguration = {
|
||||
scaleMode: PIXI.SCALE_MODES.NEAREST,
|
||||
format: PIXI.FORMATS.RGB,
|
||||
multisample: PIXI.MSAA_QUALITY.NONE
|
||||
};
|
||||
|
||||
/** @override */
|
||||
clearColor = [0, 0, 0, 0];
|
||||
|
||||
/**
|
||||
* The background color in RGB.
|
||||
* @type {[red: number, green: number, blue: number]}
|
||||
* @internal
|
||||
*/
|
||||
_backgroundColor;
|
||||
|
||||
/**
|
||||
* Track the set of HTMLVideoElements which are currently playing as part of this group.
|
||||
* @type {Set<SpriteMesh>}
|
||||
*/
|
||||
videoMeshes = new Set();
|
||||
|
||||
/**
|
||||
* Occludable objects above this elevation are faded on hover.
|
||||
* @type {number}
|
||||
*/
|
||||
hoverFadeElevation = 0;
|
||||
|
||||
/**
|
||||
* Allow API users to override the default elevation of the background layer.
|
||||
* This is a temporary solution until more formal support for scene levels is added in a future release.
|
||||
* @type {number}
|
||||
*/
|
||||
static BACKGROUND_ELEVATION = 0;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Group Attributes */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The primary background image configured for the Scene, rendered as a SpriteMesh.
|
||||
* @type {SpriteMesh}
|
||||
*/
|
||||
background;
|
||||
|
||||
/**
|
||||
* The primary foreground image configured for the Scene, rendered as a SpriteMesh.
|
||||
* @type {SpriteMesh}
|
||||
*/
|
||||
foreground;
|
||||
|
||||
/**
|
||||
* A Quadtree which partitions and organizes primary canvas objects.
|
||||
* @type {CanvasQuadtree}
|
||||
*/
|
||||
quadtree = new CanvasQuadtree();
|
||||
|
||||
/**
|
||||
* The collection of PrimaryDrawingContainer objects which are rendered in the Scene.
|
||||
* @type {Collection<string, PrimaryDrawingContainer>}
|
||||
*/
|
||||
drawings = new foundry.utils.Collection();
|
||||
|
||||
/**
|
||||
* The collection of SpriteMesh objects which are rendered in the Scene.
|
||||
* @type {Collection<string, TokenMesh>}
|
||||
*/
|
||||
tokens = new foundry.utils.Collection();
|
||||
|
||||
/**
|
||||
* The collection of SpriteMesh objects which are rendered in the Scene.
|
||||
* @type {Collection<string, PrimarySpriteMesh|TileSprite>}
|
||||
*/
|
||||
tiles = new foundry.utils.Collection();
|
||||
|
||||
/**
|
||||
* The ambience filter which is applying post-processing effects.
|
||||
* @type {PrimaryCanvasGroupAmbienceFilter}
|
||||
* @internal
|
||||
*/
|
||||
_ambienceFilter;
|
||||
|
||||
/**
|
||||
* The objects that are currently hovered in reverse sort order.
|
||||
* @type {PrimaryCanvasObjec[]>}
|
||||
*/
|
||||
#hoveredObjects = [];
|
||||
|
||||
/**
|
||||
* Trace the tiling sprite error to avoid multiple warning.
|
||||
* FIXME: Remove when the deprecation period for the tiling sprite error is over.
|
||||
* @type {boolean}
|
||||
* @internal
|
||||
*/
|
||||
#tilingSpriteError = false;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Group Properties */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Return the base HTML image or video element which provides the background texture.
|
||||
* @type {HTMLImageElement|HTMLVideoElement}
|
||||
*/
|
||||
get backgroundSource() {
|
||||
if ( !this.background.texture.valid || this.background.texture === PIXI.Texture.WHITE ) return null;
|
||||
return this.background.texture.baseTexture.resource.source;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Return the base HTML image or video element which provides the foreground texture.
|
||||
* @type {HTMLImageElement|HTMLVideoElement}
|
||||
*/
|
||||
get foregroundSource() {
|
||||
if ( !this.foreground.texture.valid ) return null;
|
||||
return this.foreground.texture.baseTexture.resource.source;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create the ambience filter bound to the primary group.
|
||||
*/
|
||||
#createAmbienceFilter() {
|
||||
if ( this._ambienceFilter ) this._ambienceFilter.enabled = false;
|
||||
else {
|
||||
this.filters ??= [];
|
||||
const f = this._ambienceFilter = PrimaryCanvasGroupAmbienceFilter.create();
|
||||
f.enabled = false;
|
||||
this.filterArea = canvas.app.renderer.screen;
|
||||
this.filters.push(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Refresh the primary mesh.
|
||||
*/
|
||||
refreshPrimarySpriteMesh() {
|
||||
const singleSource = canvas.visibility.visionModeData.source;
|
||||
const vmOptions = singleSource?.visionMode.canvas;
|
||||
const isBaseSampler = (this.sprite.shader.constructor === BaseSamplerShader);
|
||||
if ( !vmOptions && isBaseSampler ) return;
|
||||
|
||||
// Update the primary sprite shader class (or reset to BaseSamplerShader)
|
||||
this.sprite.setShaderClass(vmOptions?.shader ?? BaseSamplerShader);
|
||||
this.sprite.shader.uniforms.sampler = this.renderTexture;
|
||||
|
||||
// Need to update uniforms?
|
||||
if ( !vmOptions?.uniforms ) return;
|
||||
vmOptions.uniforms.linkedToDarknessLevel = singleSource?.visionMode.vision.darkness.adaptive;
|
||||
vmOptions.uniforms.darknessLevel = canvas.environment.darknessLevel;
|
||||
vmOptions.uniforms.darknessLevelTexture = canvas.effects.illumination.renderTexture;
|
||||
vmOptions.uniforms.screenDimensions = canvas.screenDimensions;
|
||||
|
||||
// Assigning color from source if any
|
||||
vmOptions.uniforms.tint = singleSource?.visionModeOverrides.colorRGB
|
||||
?? this.sprite.shader.constructor.defaultUniforms.tint;
|
||||
|
||||
// Updating uniforms in the primary sprite shader
|
||||
for ( const [uniform, value] of Object.entries(vmOptions?.uniforms ?? {}) ) {
|
||||
if ( uniform in this.sprite.shader.uniforms ) this.sprite.shader.uniforms[uniform] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Update this group. Calculates the canvas transform and bounds of all its children and updates the quadtree.
|
||||
*/
|
||||
update() {
|
||||
if ( this.sortDirty ) this.sortChildren();
|
||||
const children = this.children;
|
||||
for ( let i = 0, n = children.length; i < n; i++ ) {
|
||||
children[i].updateCanvasTransform?.();
|
||||
}
|
||||
canvas.masks.depth._update();
|
||||
if ( !CONFIG.debug.canvas.primary.bounds ) return;
|
||||
const dbg = canvas.controls.debug.clear().lineStyle(5, 0x30FF00);
|
||||
for ( const child of this.children ) {
|
||||
if ( child.canvasBounds ) dbg.drawShape(child.canvasBounds);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
async _draw(options) {
|
||||
this.#drawBackground();
|
||||
this.#drawForeground();
|
||||
this.#drawPadding();
|
||||
this.hoverFadeElevation = 0;
|
||||
await super._draw(options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
_render(renderer) {
|
||||
const [r, g, b] = this._backgroundColor;
|
||||
renderer.framebuffer.clear(r, g, b, 1, PIXI.BUFFER_BITS.COLOR);
|
||||
super._render(renderer);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw the Scene background image.
|
||||
*/
|
||||
#drawBackground() {
|
||||
const bg = this.background = this.addChild(new PrimarySpriteMesh({name: "background", object: this}));
|
||||
bg.elevation = this.constructor.BACKGROUND_ELEVATION;
|
||||
const bgTextureSrc = canvas.sceneTextures.background ?? canvas.scene.background.src;
|
||||
const bgTexture = bgTextureSrc instanceof PIXI.Texture ? bgTextureSrc : getTexture(bgTextureSrc);
|
||||
this.#drawSceneMesh(bg, bgTexture);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw the Scene foreground image.
|
||||
*/
|
||||
#drawForeground() {
|
||||
const fg = this.foreground = this.addChild(new PrimarySpriteMesh({name: "foreground", object: this}));
|
||||
fg.elevation = canvas.scene.foregroundElevation;
|
||||
const fgTextureSrc = canvas.sceneTextures.foreground ?? canvas.scene.foreground;
|
||||
const fgTexture = fgTextureSrc instanceof PIXI.Texture ? fgTextureSrc : getTexture(fgTextureSrc);
|
||||
|
||||
// Compare dimensions with background texture and draw the mesh
|
||||
const bg = this.background.texture;
|
||||
if ( fgTexture && bg && ((fgTexture.width !== bg.width) || (fgTexture.height !== bg.height)) ) {
|
||||
ui.notifications.warn("WARNING.ForegroundDimensionsMismatch", {localize: true});
|
||||
}
|
||||
this.#drawSceneMesh(fg, fgTexture);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw a PrimarySpriteMesh that fills the entire Scene rectangle.
|
||||
* @param {PrimarySpriteMesh} mesh The target PrimarySpriteMesh
|
||||
* @param {PIXI.Texture|null} texture The loaded Texture or null
|
||||
*/
|
||||
#drawSceneMesh(mesh, texture) {
|
||||
const d = canvas.dimensions;
|
||||
mesh.texture = texture ?? PIXI.Texture.EMPTY;
|
||||
mesh.textureAlphaThreshold = 0.75;
|
||||
mesh.occludedAlpha = 0.5;
|
||||
mesh.visible = mesh.texture !== PIXI.Texture.EMPTY;
|
||||
mesh.position.set(d.sceneX, d.sceneY);
|
||||
mesh.width = d.sceneWidth;
|
||||
mesh.height = d.sceneHeight;
|
||||
mesh.sortLayer = PrimaryCanvasGroup.SORT_LAYERS.SCENE;
|
||||
mesh.zIndex = -Infinity;
|
||||
mesh.hoverFade = false;
|
||||
|
||||
// Manage video playback
|
||||
const video = game.video.getVideoSource(mesh);
|
||||
if ( video ) {
|
||||
this.videoMeshes.add(mesh);
|
||||
game.video.play(video, {volume: game.settings.get("core", "globalAmbientVolume")});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw the Scene padding.
|
||||
*/
|
||||
#drawPadding() {
|
||||
const d = canvas.dimensions;
|
||||
const g = this.addChild(new PIXI.LegacyGraphics());
|
||||
g.beginFill(0x000000, 0.025)
|
||||
.drawShape(d.rect)
|
||||
.beginHole()
|
||||
.drawShape(d.sceneRect)
|
||||
.endHole()
|
||||
.endFill();
|
||||
g.elevation = -Infinity;
|
||||
g.sort = -Infinity;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Tear-Down */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
async _tearDown(options) {
|
||||
|
||||
// Stop video playback
|
||||
for ( const mesh of this.videoMeshes ) game.video.stop(mesh.sourceElement);
|
||||
|
||||
await super._tearDown(options);
|
||||
|
||||
// Clear collections
|
||||
this.videoMeshes.clear();
|
||||
this.tokens.clear();
|
||||
this.tiles.clear();
|
||||
|
||||
// Clear the quadtree
|
||||
this.quadtree.clear();
|
||||
|
||||
// Reset the tiling sprite tracker
|
||||
this.#tilingSpriteError = false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Token Management */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw the SpriteMesh for a specific Token object.
|
||||
* @param {Token} token The Token being added
|
||||
* @returns {PrimarySpriteMesh} The added PrimarySpriteMesh
|
||||
*/
|
||||
addToken(token) {
|
||||
const name = token.objectId;
|
||||
|
||||
// Create the token mesh
|
||||
const mesh = this.tokens.get(name) ?? this.addChild(new PrimarySpriteMesh({name, object: token}));
|
||||
mesh.texture = token.texture ?? PIXI.Texture.EMPTY;
|
||||
this.tokens.set(name, mesh);
|
||||
if ( mesh.isVideo ) this.videoMeshes.add(mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Remove a TokenMesh from the group.
|
||||
* @param {Token} token The Token being removed
|
||||
*/
|
||||
removeToken(token) {
|
||||
const name = token.objectId;
|
||||
const mesh = this.tokens.get(name);
|
||||
if ( mesh?.destroyed === false ) mesh.destroy({children: true});
|
||||
this.tokens.delete(name);
|
||||
this.videoMeshes.delete(mesh);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Tile Management */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Draw the SpriteMesh for a specific Token object.
|
||||
* @param {Tile} tile The Tile being added
|
||||
* @returns {PrimarySpriteMesh} The added PrimarySpriteMesh
|
||||
*/
|
||||
addTile(tile) {
|
||||
/** @deprecated since v12 */
|
||||
if ( !this.#tilingSpriteError && tile.document.getFlag("core", "isTilingSprite") ) {
|
||||
this.#tilingSpriteError = true;
|
||||
ui.notifications.warn("WARNING.TilingSpriteDeprecation", {localize: true, permanent: true});
|
||||
const msg = "Tiling Sprites are deprecated without replacement.";
|
||||
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14});
|
||||
}
|
||||
|
||||
const name = tile.objectId;
|
||||
let mesh = this.tiles.get(name) ?? this.addChild(new PrimarySpriteMesh({name, object: tile}));
|
||||
mesh.texture = tile.texture ?? PIXI.Texture.EMPTY;
|
||||
this.tiles.set(name, mesh);
|
||||
if ( mesh.isVideo ) this.videoMeshes.add(mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Remove a TokenMesh from the group.
|
||||
* @param {Tile} tile The Tile being removed
|
||||
*/
|
||||
removeTile(tile) {
|
||||
const name = tile.objectId;
|
||||
const mesh = this.tiles.get(name);
|
||||
if ( mesh?.destroyed === false ) mesh.destroy({children: true});
|
||||
this.tiles.delete(name);
|
||||
this.videoMeshes.delete(mesh);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Drawing Management */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Add a PrimaryGraphics to the group.
|
||||
* @param {Drawing} drawing The Drawing being added
|
||||
* @returns {PrimaryGraphics} The created PrimaryGraphics instance
|
||||
*/
|
||||
addDrawing(drawing) {
|
||||
const name = drawing.objectId;
|
||||
const shape = this.drawings.get(name) ?? this.addChild(new PrimaryGraphics({name, object: drawing}));
|
||||
this.drawings.set(name, shape);
|
||||
return shape;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Remove a PrimaryGraphics from the group.
|
||||
* @param {Drawing} drawing The Drawing being removed
|
||||
*/
|
||||
removeDrawing(drawing) {
|
||||
const name = drawing.objectId;
|
||||
if ( !this.drawings.has(name) ) return;
|
||||
const shape = this.drawings.get(name);
|
||||
if ( shape?.destroyed === false ) shape.destroy({children: true});
|
||||
this.drawings.delete(name);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Override the default PIXI.Container behavior for how objects in this container are sorted.
|
||||
* @override
|
||||
*/
|
||||
sortChildren() {
|
||||
const children = this.children;
|
||||
for ( let i = 0, n = children.length; i < n; i++ ) children[i]._lastSortedIndex = i;
|
||||
children.sort(PrimaryCanvasGroup.#compareObjects);
|
||||
this.sortDirty = false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The sorting function used to order objects inside the Primary Canvas Group.
|
||||
* Overrides the default sorting function defined for the PIXI.Container.
|
||||
* Sort Tokens PCO above other objects except WeatherEffects, then Drawings PCO, all else held equal.
|
||||
* @param {PrimaryCanvasObject|PIXI.DisplayObject} a An object to display
|
||||
* @param {PrimaryCanvasObject|PIXI.DisplayObject} b Some other object to display
|
||||
* @returns {number}
|
||||
*/
|
||||
static #compareObjects(a, b) {
|
||||
return ((a.elevation || 0) - (b.elevation || 0))
|
||||
|| ((a.sortLayer || 0) - (b.sortLayer || 0))
|
||||
|| ((a.sort || 0) - (b.sort || 0))
|
||||
|| (a.zIndex - b.zIndex)
|
||||
|| (a._lastSortedIndex - b._lastSortedIndex);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* PIXI Events */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Called when a child is added.
|
||||
* @param {PIXI.DisplayObject} child
|
||||
*/
|
||||
#onChildAdded(child) {
|
||||
if ( child.shouldRenderDepth ) canvas.masks.depth._elevationDirty = true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Called when a child is removed.
|
||||
* @param {PIXI.DisplayObject} child
|
||||
*/
|
||||
#onChildRemoved(child) {
|
||||
if ( child.shouldRenderDepth ) canvas.masks.depth._elevationDirty = true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Event Listeners and Handlers */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle mousemove events on the primary group to update the hovered state of its children.
|
||||
* @internal
|
||||
*/
|
||||
_onMouseMove() {
|
||||
const time = canvas.app.ticker.lastTime;
|
||||
|
||||
// Unset the hovered state of the hovered PCOs
|
||||
for ( const object of this.#hoveredObjects ) {
|
||||
if ( !object._hoverFadeState.hovered ) continue;
|
||||
object._hoverFadeState.hovered = false;
|
||||
object._hoverFadeState.hoveredTime = time;
|
||||
}
|
||||
|
||||
this.#updateHoveredObjects();
|
||||
|
||||
// Set the hovered state of the hovered PCOs
|
||||
for ( const object of this.#hoveredObjects ) {
|
||||
if ( !object.hoverFade || !(object.elevation > this.hoverFadeElevation) ) break;
|
||||
object._hoverFadeState.hovered = true;
|
||||
object._hoverFadeState.hoveredTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Update the hovered objects. Returns the hovered objects.
|
||||
*/
|
||||
#updateHoveredObjects() {
|
||||
this.#hoveredObjects.length = 0;
|
||||
|
||||
// Get all PCOs that contain the mouse position
|
||||
const position = canvas.mousePosition;
|
||||
const collisionTest = ({t}) => t.visible && t.renderable
|
||||
&& t._hoverFadeState && t.containsCanvasPoint(position);
|
||||
for ( const object of canvas.primary.quadtree.getObjects(
|
||||
new PIXI.Rectangle(position.x, position.y, 0, 0), {collisionTest}
|
||||
)) {
|
||||
this.#hoveredObjects.push(object);
|
||||
}
|
||||
|
||||
// Sort the hovered PCOs in reverse primary order
|
||||
this.#hoveredObjects.sort((a, b) => PrimaryCanvasGroup.#compareObjects(b, a));
|
||||
|
||||
// Discard hit objects below the hovered placeable
|
||||
const hoveredPlaceable = canvas.activeLayer?.hover;
|
||||
if ( hoveredPlaceable ) {
|
||||
let elevation = 0;
|
||||
let sortLayer = Infinity;
|
||||
let sort = Infinity;
|
||||
let zIndex = Infinity;
|
||||
if ( (hoveredPlaceable instanceof Token) || (hoveredPlaceable instanceof Tile) ) {
|
||||
const mesh = hoveredPlaceable.mesh;
|
||||
if ( mesh ) {
|
||||
elevation = mesh.elevation;
|
||||
sortLayer = mesh.sortLayer;
|
||||
sort = mesh.sort;
|
||||
zIndex = mesh.zIndex;
|
||||
}
|
||||
} else if ( hoveredPlaceable instanceof Drawing ) {
|
||||
const shape = hoveredPlaceable.shape;
|
||||
if ( shape ) {
|
||||
elevation = shape.elevation;
|
||||
sortLayer = shape.sortLayer;
|
||||
sort = shape.sort;
|
||||
zIndex = shape.zIndex;
|
||||
}
|
||||
} else if ( hoveredPlaceable.document.schema.has("elevation") ) {
|
||||
elevation = hoveredPlaceable.document.elevation;
|
||||
}
|
||||
const threshold = {elevation, sortLayer, sort, zIndex, _lastSortedIndex: Infinity};
|
||||
while ( this.#hoveredObjects.length
|
||||
&& PrimaryCanvasGroup.#compareObjects(this.#hoveredObjects.at(-1), threshold) <= 0 ) {
|
||||
this.#hoveredObjects.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Deprecations and Compatibility */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @deprecated since v12
|
||||
* @ignore
|
||||
*/
|
||||
mapElevationToDepth(elevation) {
|
||||
const msg = "PrimaryCanvasGroup#mapElevationAlpha is deprecated. "
|
||||
+ "Use canvas.masks.depth.mapElevation(elevation) instead.";
|
||||
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14});
|
||||
return canvas.masks.depth.mapElevation(elevation);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @deprecated since v11
|
||||
* @ignore
|
||||
*/
|
||||
mapElevationAlpha(elevation) {
|
||||
const msg = "PrimaryCanvasGroup#mapElevationAlpha is deprecated. "
|
||||
+ "Use canvas.masks.depth.mapElevation(elevation) instead.";
|
||||
foundry.utils.logCompatibilityWarning(msg, {since: 11, until: 13});
|
||||
return canvas.masks.depth.mapElevation(elevation);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user