refactor(ui): split up canvas entity renderers, temp disable preview

This commit is contained in:
psychedelicious 2024-06-17 16:49:07 +10:00
parent 15ad4e3f5e
commit 007e2553a8
8 changed files with 109 additions and 33 deletions

View File

@ -5,7 +5,14 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { HeadsUpDisplay } from 'features/controlLayers/components/HeadsUpDisplay';
import { setStageEventHandlers } from 'features/controlLayers/konva/events';
import { renderBackgroundLayer } from 'features/controlLayers/konva/renderers/background';
import { debouncedRenderers, renderers as normalRenderers } from 'features/controlLayers/konva/renderers/layers';
import { renderControlAdapters } from 'features/controlLayers/konva/renderers/caLayer';
import {
arrangeEntities,
debouncedRenderers,
renderers as normalRenderers,
} from 'features/controlLayers/konva/renderers/layers';
import { renderLayers } from 'features/controlLayers/konva/renderers/rasterLayer';
import { renderRegions } from 'features/controlLayers/konva/renderers/rgLayer';
import {
$bbox,
$currentFill,
@ -352,18 +359,22 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null,
useLayoutEffect(() => {
log.trace('Rendering layers');
renderers.renderLayers(
stage,
layers,
controlAdapters,
regions,
maskOpacity,
tool.selected,
selectedEntity,
getImageDTO,
onPosChanged
);
}, [controlAdapters, layers, maskOpacity, onPosChanged, regions, renderers, selectedEntity, stage, tool.selected]);
renderLayers(stage, layers, tool.selected, onPosChanged);
}, [layers, onPosChanged, stage, tool.selected]);
useLayoutEffect(() => {
log.trace('Rendering regions');
renderRegions(stage, regions, maskOpacity, tool.selected, selectedEntity, onPosChanged);
}, [maskOpacity, onPosChanged, regions, selectedEntity, stage, tool.selected]);
useLayoutEffect(() => {
log.trace('Rendering layers');
renderControlAdapters(stage, controlAdapters, getImageDTO);
}, [controlAdapters, stage]);
useLayoutEffect(() => {
arrangeEntities(stage, layers, controlAdapters, regions);
}, [layers, controlAdapters, regions, stage]);
// useLayoutEffect(() => {
// if (asPreview) {

View File

@ -43,6 +43,8 @@ export const RASTER_LAYER_IMAGE_NAME = 'raster_layer.image';
export const INPAINT_MASK_LAYER_NAME = 'inpaint_mask_layer';
export const BACKGROUND_LAYER_ID = 'background_layer';
// Getters for non-singleton layer and object IDs
export const getRGId = (entityId: string) => `${RG_LAYER_NAME}_${entityId}`;
export const getLayerId = (entityId: string) => `${RASTER_LAYER_NAME}_${entityId}`;

View File

@ -1,4 +1,5 @@
import { getArbitraryBaseColor } from '@invoke-ai/ui-library';
import { BACKGROUND_LAYER_ID } from 'features/controlLayers/konva/naming';
import Konva from 'konva';
const baseGridLineColor = getArbitraryBaseColor(27);
@ -23,13 +24,13 @@ const getGridSpacing = (scale: number): number => {
return 256;
};
const getBackgroundLayer = (stage: Konva.Stage): Konva.Layer => {
let background = stage.findOne<Konva.Layer>('#background');
export const getBackgroundLayer = (stage: Konva.Stage): Konva.Layer => {
let background = stage.findOne<Konva.Layer>(`#${BACKGROUND_LAYER_ID}`);
if (background) {
return background;
}
background = new Konva.Layer({ id: 'background' });
background = new Konva.Layer({ id: BACKGROUND_LAYER_ID });
stage.add(background);
return background;
};

View File

@ -92,10 +92,9 @@ const updateCALayerImageSource = async (
const updateCALayerImageAttrs = (stage: Konva.Stage, konvaImage: Konva.Image, ca: ControlAdapterData): void => {
let needsCache = false;
// Konva erroneously reports NaN for width and height when the stage is hidden. This causes errors when caching,
// but it doesn't seem to break anything.
// TODO(psyche): Investigate and report upstream.
const filter = konvaImage.filters()[0] ?? null;
// TODO(psyche): `node.filters()` returns null if no filters; report upstream
const filters = konvaImage.filters() ?? [];
const filter = filters[0] ?? null;
const filterNeedsUpdate = (filter === null && ca.filter !== 'none') || (filter && filter.name !== ca.filter);
if (
konvaImage.x() !== ca.x ||
@ -130,13 +129,9 @@ const updateCALayerImageAttrs = (stage: Konva.Stage, konvaImage: Konva.Image, ca
export const renderCALayer = (
stage: Konva.Stage,
ca: ControlAdapterData,
zIndex: number,
getImageDTO: (imageName: string) => Promise<ImageDTO | null>
): void => {
const konvaLayer = stage.findOne<Konva.Layer>(`#${ca.id}`) ?? createCALayer(stage, ca);
konvaLayer.zIndex(zIndex);
const konvaImage = konvaLayer.findOne<Konva.Image>(`.${CA_LAYER_IMAGE_NAME}`);
const canvasImageSource = konvaImage?.image();
@ -159,3 +154,19 @@ export const renderCALayer = (
updateCALayerImageAttrs(stage, konvaImage, ca);
}
};
export const renderControlAdapters = (
stage: Konva.Stage,
controlAdapters: ControlAdapterData[],
getImageDTO: (imageName: string) => Promise<ImageDTO | null>
): void => {
// Destroy nonexistent layers
for (const konvaLayer of stage.find<Konva.Layer>(`.${CA_LAYER_NAME}`)) {
if (!controlAdapters.find((ca) => ca.id === konvaLayer.id())) {
konvaLayer.destroy();
}
}
for (const ca of controlAdapters) {
renderCALayer(stage, ca, getImageDTO);
}
};

View File

@ -1,5 +1,5 @@
import { DEBOUNCE_MS } from 'features/controlLayers/konva/constants';
import { PREVIEW_LAYER_ID } from 'features/controlLayers/konva/naming';
import { BACKGROUND_LAYER_ID, PREVIEW_LAYER_ID } from 'features/controlLayers/konva/naming';
import { updateBboxes } from 'features/controlLayers/konva/renderers/bbox';
import { renderCALayer } from 'features/controlLayers/konva/renderers/caLayer';
import { renderBboxPreview, renderToolPreview } from 'features/controlLayers/konva/renderers/previewLayer';
@ -93,3 +93,23 @@ const getDebouncedRenderers = (ms = DEBOUNCE_MS): typeof renderers => ({
* All the renderers for the Konva stage, debounced.
*/
export const debouncedRenderers: typeof renderers = getDebouncedRenderers();
export const arrangeEntities = (
stage: Konva.Stage,
layers: LayerData[],
controlAdapters: ControlAdapterData[],
regions: RegionalGuidanceData[]
): void => {
let zIndex = 0;
stage.findOne<Konva.Layer>(`#${BACKGROUND_LAYER_ID}`)?.zIndex(++zIndex);
for (const layer of layers) {
stage.findOne<Konva.Layer>(`#${layer.id}`)?.zIndex(++zIndex);
}
for (const ca of controlAdapters) {
stage.findOne<Konva.Layer>(`#${ca.id}`)?.zIndex(++zIndex);
}
for (const rg of regions) {
stage.findOne<Konva.Layer>(`#${rg.id}`)?.zIndex(++zIndex);
}
stage.findOne<Konva.Layer>(`#${PREVIEW_LAYER_ID}`)?.zIndex(++zIndex);
};

View File

@ -64,7 +64,6 @@ export const renderRasterLayer = async (
stage: Konva.Stage,
layerState: LayerData,
tool: Tool,
zIndex: number,
onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void
) => {
const konvaLayer =
@ -75,7 +74,6 @@ export const renderRasterLayer = async (
listening: tool === 'move', // The layer only listens when using the move tool - otherwise the stage is handling mouse events
x: Math.floor(layerState.x),
y: Math.floor(layerState.y),
zIndex,
});
const konvaObjectGroup =
@ -145,3 +143,20 @@ export const renderRasterLayer = async (
konvaObjectGroup.opacity(layerState.opacity);
};
export const renderLayers = (
stage: Konva.Stage,
layers: LayerData[],
tool: Tool,
onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void
): void => {
// Destroy nonexistent layers
for (const konvaLayer of stage.find<Konva.Layer>(`.${RASTER_LAYER_NAME}`)) {
if (!layers.find((l) => l.id === konvaLayer.id())) {
konvaLayer.destroy();
}
}
for (const layer of layers) {
renderRasterLayer(stage, layer, tool, onPosChanged);
}
};

View File

@ -83,7 +83,6 @@ export const renderRGLayer = (
rg: RegionalGuidanceData,
globalMaskLayerOpacity: number,
tool: Tool,
zIndex: number,
selectedEntity: CanvasEntity | null,
onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void
): void => {
@ -94,7 +93,6 @@ export const renderRGLayer = (
listening: tool === 'move', // The layer only listens when using the move tool - otherwise the stage is handling mouse events
x: Math.floor(rg.x),
y: Math.floor(rg.y),
zIndex,
});
// Convert the color to a string, stripping the alpha - the object group will handle opacity.
@ -233,3 +231,22 @@ export const renderRGLayer = (
bboxRect.visible(false);
}
};
export const renderRegions = (
stage: Konva.Stage,
regions: RegionalGuidanceData[],
maskOpacity: number,
tool: Tool,
selectedEntity: CanvasEntity | null,
onPosChanged?: (arg: PosChangedArg, entityType: CanvasEntity['type']) => void
): void => {
// Destroy nonexistent layers
for (const konvaLayer of stage.find<Konva.Layer>(`.${RG_LAYER_NAME}`)) {
if (!regions.find((rg) => rg.id === konvaLayer.id())) {
konvaLayer.destroy();
}
}
for (const rg of regions) {
renderRGLayer(stage, rg, maskOpacity, tool, selectedEntity, onPosChanged);
}
};

View File

@ -2,15 +2,14 @@ import { Flex } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { StageComponent } from 'features/controlLayers/components/StageComponent';
import { $isPreviewVisible } from 'features/controlLayers/store/canvasV2Slice';
import { AspectRatioIconPreview } from 'features/parameters/components/ImageSize/AspectRatioIconPreview';
import { memo } from 'react';
export const AspectRatioCanvasPreview = memo(() => {
const isPreviewVisible = useStore($isPreviewVisible);
if (!isPreviewVisible) {
return <AspectRatioIconPreview />;
}
// if (!isPreviewVisible) {
// return <AspectRatioIconPreview />;
// }
return (
<Flex w="full" h="full" alignItems="center" justifyContent="center" position="relative">