107 lines
3.1 KiB
TypeScript
107 lines
3.1 KiB
TypeScript
|
|
import { create } from 'zustand';
|
||
|
|
import { DirtyRectManager, type DirtyRect } from '@/lib/dirty-rect';
|
||
|
|
|
||
|
|
interface RenderState {
|
||
|
|
/** Dirty rectangle manager instance */
|
||
|
|
dirtyRectManager: DirtyRectManager | null;
|
||
|
|
/** Whether dirty rect optimization is enabled */
|
||
|
|
enableDirtyRects: boolean;
|
||
|
|
/** Frame counter for debugging */
|
||
|
|
frameCount: number;
|
||
|
|
/** Last render time */
|
||
|
|
lastRenderTime: number;
|
||
|
|
|
||
|
|
/** Initialize dirty rect manager */
|
||
|
|
initDirtyRects: (canvasWidth: number, canvasHeight: number) => void;
|
||
|
|
/** Mark a region as dirty */
|
||
|
|
markDirty: (x: number, y: number, width: number, height: number) => void;
|
||
|
|
/** Mark entire canvas as dirty */
|
||
|
|
markAllDirty: () => void;
|
||
|
|
/** Clear all dirty regions */
|
||
|
|
clearDirtyRects: () => void;
|
||
|
|
/** Check if anything is dirty */
|
||
|
|
isDirty: () => boolean;
|
||
|
|
/** Get dirty regions for rendering */
|
||
|
|
getDirtyRegions: () => DirtyRect[];
|
||
|
|
/** Update canvas size */
|
||
|
|
updateCanvasSize: (width: number, height: number) => void;
|
||
|
|
/** Toggle dirty rect optimization */
|
||
|
|
toggleDirtyRects: () => void;
|
||
|
|
/** Increment frame counter */
|
||
|
|
incrementFrame: () => void;
|
||
|
|
/** Update render time */
|
||
|
|
setRenderTime: (time: number) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const useRenderStore = create<RenderState>((set, get) => ({
|
||
|
|
dirtyRectManager: null,
|
||
|
|
enableDirtyRects: true,
|
||
|
|
frameCount: 0,
|
||
|
|
lastRenderTime: 0,
|
||
|
|
|
||
|
|
initDirtyRects: (canvasWidth: number, canvasHeight: number) => {
|
||
|
|
set({
|
||
|
|
dirtyRectManager: new DirtyRectManager(canvasWidth, canvasHeight),
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
markDirty: (x: number, y: number, width: number, height: number) => {
|
||
|
|
const { dirtyRectManager, enableDirtyRects } = get();
|
||
|
|
if (dirtyRectManager && enableDirtyRects) {
|
||
|
|
dirtyRectManager.markDirty(x, y, width, height);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
markAllDirty: () => {
|
||
|
|
const { dirtyRectManager } = get();
|
||
|
|
if (dirtyRectManager) {
|
||
|
|
dirtyRectManager.markAllDirty();
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
clearDirtyRects: () => {
|
||
|
|
const { dirtyRectManager } = get();
|
||
|
|
if (dirtyRectManager) {
|
||
|
|
dirtyRectManager.clear();
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
isDirty: () => {
|
||
|
|
const { dirtyRectManager, enableDirtyRects } = get();
|
||
|
|
if (!enableDirtyRects) return true; // Always dirty if optimization is off
|
||
|
|
return dirtyRectManager ? dirtyRectManager.isDirty() : true;
|
||
|
|
},
|
||
|
|
|
||
|
|
getDirtyRegions: () => {
|
||
|
|
const { dirtyRectManager, enableDirtyRects } = get();
|
||
|
|
if (!enableDirtyRects || !dirtyRectManager) {
|
||
|
|
// Return full canvas if optimization is off
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
return dirtyRectManager.getDirtyRegions();
|
||
|
|
},
|
||
|
|
|
||
|
|
updateCanvasSize: (width: number, height: number) => {
|
||
|
|
const { dirtyRectManager } = get();
|
||
|
|
if (dirtyRectManager) {
|
||
|
|
dirtyRectManager.setCanvasSize(width, height);
|
||
|
|
dirtyRectManager.markAllDirty(); // Mark everything dirty on resize
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
toggleDirtyRects: () => {
|
||
|
|
set((state) => ({
|
||
|
|
enableDirtyRects: !state.enableDirtyRects,
|
||
|
|
}));
|
||
|
|
get().markAllDirty(); // Force full redraw after toggle
|
||
|
|
},
|
||
|
|
|
||
|
|
incrementFrame: () => {
|
||
|
|
set((state) => ({ frameCount: state.frameCount + 1 }));
|
||
|
|
},
|
||
|
|
|
||
|
|
setRenderTime: (time: number) => {
|
||
|
|
set({ lastRenderTime: time });
|
||
|
|
},
|
||
|
|
}));
|