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(); } }