fleeting-garden/src/game-loop/simulation-frame.ts

85 lines
3.2 KiB
TypeScript

import { AgentPipeline } from '../pipelines/agents/agent-pipeline';
import { BrushPipeline } from '../pipelines/brush/brush-pipeline';
import { DiffusionPipeline } from '../pipelines/diffusion/diffusion-pipeline';
import { EraserAgentPipeline } from '../pipelines/eraser/eraser-agent-pipeline';
import { EraserTexturePipeline } from '../pipelines/eraser/eraser-texture-pipeline';
import { RenderPipeline } from '../pipelines/render/render-pipeline';
import { CanvasReadbackRequest } from './game-loop-types';
import { SimulationTextures } from './simulation-textures';
interface SimulationFramePipelines {
agentPipeline: AgentPipeline;
brushPipeline: BrushPipeline;
eraserAgentPipeline: EraserAgentPipeline;
eraserTexturePipeline: EraserTexturePipeline;
diffusionPipeline: DiffusionPipeline;
brushEffectDiffusionPipeline: DiffusionPipeline;
renderPipeline: RenderPipeline;
}
export class SimulationFrameRenderer {
public constructor(
private readonly device: GPUDevice,
private readonly textures: SimulationTextures,
private readonly pipelines: SimulationFramePipelines
) {}
public execute(
isErasing: boolean,
canvasReadbackRequest?: CanvasReadbackRequest | null
): void {
const commandEncoder = this.device.createCommandEncoder();
this.textures.copyTrailMapAToB(commandEncoder);
if (isErasing) {
if (this.pipelines.eraserAgentPipeline.hasActiveMask()) {
const eraserMask = this.textures.clearEraserMask(commandEncoder);
this.pipelines.eraserTexturePipeline.execute(commandEncoder, eraserMask);
this.pipelines.eraserTexturePipeline.executeMultiTarget(
commandEncoder,
this.textures.sourceMapA.getTextureView(),
this.textures.influenceMapA.getTextureView(),
this.textures.trailMapB.getTextureView()
);
this.pipelines.eraserAgentPipeline.execute(commandEncoder, eraserMask);
}
} else {
this.pipelines.brushPipeline.executeMultiTarget(
commandEncoder,
this.textures.sourceMapA.getTextureView(),
this.textures.influenceMapA.getTextureView()
);
}
this.pipelines.agentPipeline.execute(
commandEncoder,
this.textures.trailMapA.getTextureView(),
this.textures.trailMapB.getTextureView(),
this.textures.influenceMapA.getTextureView()
);
this.pipelines.diffusionPipeline.execute(
commandEncoder,
this.textures.trailMapB.getTextureView(),
this.textures.trailMapA.getTextureView()
);
const canvasTexture = this.pipelines.renderPipeline.execute(
commandEncoder,
this.textures.trailMapA.getTextureView(),
this.textures.sourceMapA.getTextureView()
);
canvasReadbackRequest?.encode(commandEncoder, canvasTexture);
this.pipelines.diffusionPipeline.execute(
commandEncoder,
this.textures.sourceMapA.getTextureView(),
this.textures.sourceMapB.getTextureView()
);
this.pipelines.brushEffectDiffusionPipeline.execute(
commandEncoder,
this.textures.influenceMapA.getTextureView(),
this.textures.influenceMapB.getTextureView()
);
this.device.queue.submit([commandEncoder.finish()]);
canvasReadbackRequest?.afterSubmit();
this.textures.swapBrushEffectMaps();
}
}