Clean up
This commit is contained in:
parent
ea0304356f
commit
7c70f15e49
65 changed files with 1122 additions and 1906 deletions
|
|
@ -1,32 +1,33 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
|
||||
import { GardenAudio } from '../audio/garden-audio';
|
||||
import { gardenAudioConfig } from '../audio/garden-audio-config';
|
||||
import { appConfig } from '../config';
|
||||
import { activeVibe, settings } from '../settings';
|
||||
import { DeltaTimeCalculator } from '../utils/delta-time-calculator';
|
||||
import { rgbColorToCss, type RgbColor } from '../utils/rgb-color';
|
||||
import { AgentPopulation } from './agent-population';
|
||||
import { DevStatsOverlay } from './dev-stats-overlay';
|
||||
import { EraserPointerPreviewController } from './eraser-pointer-preview-controller';
|
||||
import { EraserPreview } from './eraser-preview';
|
||||
import { Export4KRenderer } from './export-4k-renderer';
|
||||
import { ExportSnapshotRenderer } from './export-snapshot-renderer';
|
||||
import { FramePerformance } from './frame-performance';
|
||||
import { GameLoopResources } from './game-loop-resources';
|
||||
import { GardenUi } from './game-loop-types';
|
||||
import { getInternalRenderSize } from './internal-render-size';
|
||||
import { IntroPrompt } from './intro-prompt';
|
||||
import { GardenPointerInput } from './pointer-input';
|
||||
import { RenderInputCache } from './render-input-cache';
|
||||
import { PipelineStrokeOutput } from './stroke-output';
|
||||
import { ToolbarContrastMonitor } from './toolbar-contrast-monitor';
|
||||
|
||||
export default class GameLoop {
|
||||
private readonly resources: GameLoopResources;
|
||||
private readonly audio = new GardenAudio(gardenAudioConfig);
|
||||
private readonly renderInputs = new RenderInputCache();
|
||||
private readonly audio = new GardenAudio(appConfig.audio);
|
||||
private readonly introPrompt: IntroPrompt;
|
||||
private readonly eraserPreview: EraserPreview;
|
||||
private readonly pointerInput: GardenPointerInput;
|
||||
private readonly eraserPreviewController: EraserPointerPreviewController;
|
||||
private readonly agentPopulation: AgentPopulation;
|
||||
private readonly export4KRenderer: Export4KRenderer;
|
||||
private readonly exportSnapshotRenderer: ExportSnapshotRenderer;
|
||||
private readonly framePerformance = new FramePerformance();
|
||||
private readonly devStatsOverlay: DevStatsOverlay | null;
|
||||
private readonly toolbarContrastMonitor: ToolbarContrastMonitor;
|
||||
|
|
@ -35,6 +36,7 @@ export default class GameLoop {
|
|||
private readonly resizeListener = this.resize.bind(this);
|
||||
|
||||
private pendingIntroResizeAt: DOMHighResTimeStamp | null = null;
|
||||
private previousAccentColor = '';
|
||||
private hasFinished = false;
|
||||
private readonly finished = Promise.withResolvers<void>();
|
||||
|
||||
|
|
@ -48,38 +50,53 @@ export default class GameLoop {
|
|||
this.devStatsOverlay = import.meta.env.DEV
|
||||
? new DevStatsOverlay(canvas.parentElement ?? document.body)
|
||||
: null;
|
||||
this.resources = new GameLoopResources(canvas, device, this.canvasSize);
|
||||
this.resources = new GameLoopResources(
|
||||
canvas,
|
||||
device,
|
||||
this.canvasSize,
|
||||
this.framePerformance.adaptiveCapInitial
|
||||
);
|
||||
this.introPrompt = new IntroPrompt(ui.prompt);
|
||||
this.eraserPreview = new EraserPreview(canvas, ui.eraserPreview);
|
||||
this.toolbarContrastMonitor = new ToolbarContrastMonitor(canvas, ui.toolbar, device);
|
||||
this.agentPopulation = new AgentPopulation(
|
||||
this.resources.agentGenerationPipeline,
|
||||
this.seedValue,
|
||||
() => this.canvasPixelRatio
|
||||
() => this.canvasPixelRatio,
|
||||
this.framePerformance
|
||||
);
|
||||
this.agentPopulation.initializeIntroAgents(this.canvasSize);
|
||||
this.pointerInput = new GardenPointerInput({
|
||||
canvas,
|
||||
audio: this.audio,
|
||||
brushPipeline: this.resources.brushPipeline,
|
||||
eraserAgentPipeline: this.resources.eraserAgentPipeline,
|
||||
eraserTexturePipeline: this.resources.eraserTexturePipeline,
|
||||
eraserPreview: this.eraserPreview,
|
||||
strokeOutput: new PipelineStrokeOutput(
|
||||
this.resources.brushPipeline,
|
||||
this.resources.eraserAgentPipeline,
|
||||
this.resources.eraserTexturePipeline
|
||||
),
|
||||
getCanvasPixelRatio: () => this.canvasPixelRatio,
|
||||
getMirrorSegmentCount: () => this.mirrorSegmentCount,
|
||||
onStartDrawing: () => this.introPrompt.markStartedDrawing(),
|
||||
onEraseGestureEnded: () => this.agentPopulation.requestCompactionAfterErase(),
|
||||
spawnStrokeAgents: (from, to) => this.agentPopulation.spawnStrokeAgents(from, to),
|
||||
});
|
||||
this.export4KRenderer = new Export4KRenderer({
|
||||
this.eraserPreviewController = new EraserPointerPreviewController({
|
||||
canvas,
|
||||
eraserPreview: this.eraserPreview,
|
||||
getIsSwipeActive: () => this.pointerInput.isSwipeActive,
|
||||
});
|
||||
this.exportSnapshotRenderer = new ExportSnapshotRenderer({
|
||||
device,
|
||||
renderPipeline: this.resources.renderPipeline,
|
||||
statusElement: ui.exportStatus,
|
||||
seed: this.seed,
|
||||
getSourceSize: () => ({
|
||||
width: this.canvas.width,
|
||||
height: this.canvas.height,
|
||||
}),
|
||||
getSourceSize: () => {
|
||||
const size = this.resources.textures.trailMapA.getSize();
|
||||
return {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
};
|
||||
},
|
||||
getColorTextureView: () => this.resources.textures.trailMapA.getTextureView(),
|
||||
getSourceTextureView: () => this.resources.textures.sourceMapA.getTextureView(),
|
||||
getVibeId: () => activeVibe.id,
|
||||
|
|
@ -87,18 +104,19 @@ export default class GameLoop {
|
|||
|
||||
window.addEventListener('resize', this.resizeListener);
|
||||
this.pointerInput.attach();
|
||||
this.eraserPreviewController.attach();
|
||||
}
|
||||
|
||||
public setEraseMode(isErasing: boolean): void {
|
||||
this.pointerInput.setEraseMode(isErasing);
|
||||
this.eraserPreviewController.setEraseMode(isErasing);
|
||||
}
|
||||
|
||||
public updateEraserPreview(event?: PointerEvent): void {
|
||||
this.pointerInput.updateEraserPreview(event);
|
||||
this.eraserPreviewController.update(event);
|
||||
}
|
||||
|
||||
public onVibeChanged(): void {
|
||||
this.renderInputs.invalidate();
|
||||
this.agentPopulation.onVibeChanged();
|
||||
}
|
||||
|
||||
|
|
@ -123,8 +141,8 @@ export default class GameLoop {
|
|||
return this.finished.promise;
|
||||
}
|
||||
|
||||
public async export4K(): Promise<void> {
|
||||
return this.export4KRenderer.export();
|
||||
public async exportSnapshot(): Promise<void> {
|
||||
return this.exportSnapshotRenderer.export();
|
||||
}
|
||||
|
||||
public async destroy(): Promise<void> {
|
||||
|
|
@ -133,6 +151,7 @@ export default class GameLoop {
|
|||
|
||||
window.removeEventListener('resize', this.resizeListener);
|
||||
this.pointerInput.detach();
|
||||
this.eraserPreviewController.detach();
|
||||
this.devStatsOverlay?.destroy();
|
||||
this.toolbarContrastMonitor.destroy();
|
||||
this.introPrompt.destroy();
|
||||
|
|
@ -149,22 +168,20 @@ export default class GameLoop {
|
|||
|
||||
const deltaTime = this.deltaTimeCalculator.calculateDeltaTimeInSeconds(time);
|
||||
this.framePerformance.update(time);
|
||||
this.agentPopulation.growBudget(
|
||||
this.framePerformance.frameDeltaSeconds,
|
||||
this.framePerformance.smoothedFps
|
||||
);
|
||||
this.agentPopulation.updateAdaptiveCap();
|
||||
this.introPrompt.update(this.pendingIntroResizeAt === null ? deltaTime : 0);
|
||||
this.resize();
|
||||
this.resizeSimulationToCanvas(time);
|
||||
this.regenerateIntroAfterSettledResize(time);
|
||||
|
||||
const { channelColors, backgroundColor } = this.renderInputs.get();
|
||||
const channelColors = activeVibe.colors;
|
||||
const backgroundColor = activeVibe.backgroundColor;
|
||||
const introProgress = this.introPrompt.progress;
|
||||
const canvasPixelRatio = this.canvasPixelRatio;
|
||||
const eraserPixelSize = settings.eraserSize * canvasPixelRatio;
|
||||
const isErasing = this.pointerInput.isEraseMode;
|
||||
const accentColor = channelColors[settings.selectedColorIndex] ?? channelColors[0];
|
||||
this.renderInputs.updateAccentColor(accentColor);
|
||||
this.updateAccentColor(accentColor);
|
||||
this.audio.update({
|
||||
vibe: activeVibe,
|
||||
isErasing,
|
||||
|
|
@ -203,6 +220,16 @@ export default class GameLoop {
|
|||
requestAnimationFrame(this.render);
|
||||
};
|
||||
|
||||
private updateAccentColor(color: RgbColor): void {
|
||||
const accentColor = rgbColorToCss(color);
|
||||
if (this.previousAccentColor === accentColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.previousAccentColor = accentColor;
|
||||
document.documentElement.style.setProperty('--accent-color', accentColor);
|
||||
}
|
||||
|
||||
private resize(): void {
|
||||
const rect = this.canvas.getBoundingClientRect();
|
||||
const { width, height } = getInternalRenderSize({
|
||||
|
|
|
|||
Loading…
Reference in a new issue