mirror of
https://github.com/igorski/bitmappery.git
synced 2026-08-06 00:09:39 +02:00
122 lines
4.8 KiB
TypeScript
122 lines
4.8 KiB
TypeScript
/**
|
|
* The MIT License (MIT)
|
|
*
|
|
* Igor Zinken 2025-2026 - https://www.igorski.nl
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
import { type Layer } from "@/model/types/layer";
|
|
|
|
interface BlendedLayerCache {
|
|
enabled: boolean; // whether blend caching is enabled for the current Document
|
|
paused: boolean; // whether blend caching is paused (for instance during mutations of layers inside the blended content)
|
|
index: number; // index of highest layer containing the blended content
|
|
bitmap?: HTMLCanvasElement; // cached Bitmap
|
|
blendableLayers?: number[]; // indices of all layers to render in the blend (up to and including the layer defined at the cache index)
|
|
};
|
|
|
|
const blendCache: BlendedLayerCache = {
|
|
enabled: false,
|
|
paused: false,
|
|
index: -1,
|
|
bitmap: undefined,
|
|
blendableLayers: undefined,
|
|
};
|
|
|
|
export const useBlendCaching = (): boolean => !blendCache.paused && blendCache.enabled;
|
|
|
|
export const setBlendCaching = ( value: boolean, blendableLayers?: Layer[] ): void => {
|
|
blendCache.enabled = value;
|
|
if ( !value ) {
|
|
blendCache.index = -1;
|
|
}
|
|
blendCache.blendableLayers = blendableLayers?.map(( _layer, index ) => index );
|
|
};
|
|
|
|
export const getBlendableLayers = (): number[] | undefined => {
|
|
return blendCache.blendableLayers;
|
|
};
|
|
|
|
/**
|
|
* Whether the layer at provided index is part of the blended layer cache. Note that
|
|
* excludes the index of the layer that has the cached blend. This is for easy diffing
|
|
* and cache generation purposes (see LayerRenderer#draw())
|
|
*
|
|
* In other words, this function determines whether the provided index is of a layer below
|
|
* the highest layer that has a cached blend mode applied.
|
|
*/
|
|
export const isBlendCached = ( index: number ): boolean => {
|
|
return index < blendCache.index;
|
|
};
|
|
|
|
/**
|
|
* Whether the Layer at provided index affects the state of the blend cache
|
|
* (similar to isBlendCached() but also includes the highest layer that has the cached blend mode)
|
|
*/
|
|
export const affectsBlendCache = ( index: number ): boolean => {
|
|
return index <= blendCache.index;
|
|
};
|
|
|
|
export const pauseBlendCaching = ( index: number, paused: boolean ): void => {
|
|
const isCached = blendCache.index === index || isBlendCached( index );
|
|
if ( !isCached ) {
|
|
return;
|
|
}
|
|
const wasPaused = blendCache.paused;
|
|
blendCache.paused = paused;
|
|
|
|
if ( wasPaused && !paused ) {
|
|
flushBlendedLayerCache();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Retrieve the cached bitmap corresponding to the layer at provided index.
|
|
* When existing, the bitmap will return the contents of the layer as well as that
|
|
* of all underlying layers. Note: if the Layer at provided index has a blend mode filter
|
|
* but no cached bitmap, it means a Layer w/blend mode filter at a higher index owns the cache.
|
|
*/
|
|
export const getBlendCache = ( index: number ): HTMLCanvasElement | undefined => {
|
|
if ( blendCache.index !== index ) {
|
|
return;
|
|
}
|
|
return blendCache.bitmap;
|
|
};
|
|
|
|
/**
|
|
* Cache provided bitmap and associate its ownership with the layer at the provided index.
|
|
* If a subsequent invocation for a layer at a higher index is provided, this is fine
|
|
* as an underlying layer with its own blended context would be cached within the higher layers bitmap.
|
|
*/
|
|
export const cacheBlendedLayer = ( index: number, bitmap: HTMLCanvasElement ): void => {
|
|
blendCache.index = index;
|
|
blendCache.bitmap = bitmap;
|
|
};
|
|
|
|
/**
|
|
* Clear the existing blend cache bitmap so it can be regenerated on next render.
|
|
* When requesting a full flush, the blend layer index is also unset.
|
|
* Note this does not unset the enabled state so LayerRenderers can take appropriate action upon next render.
|
|
*/
|
|
export const flushBlendedLayerCache = ( full = false ): void => {
|
|
if ( full ) {
|
|
blendCache.index = -1;
|
|
}
|
|
blendCache.bitmap = undefined;
|
|
};
|