feat: add grid size slider for dynamic grid size adjustment

This commit is contained in:
Florian Sylvain
2025-04-06 06:04:04 +02:00
parent 848df82509
commit d8960493dd
2 changed files with 64 additions and 10 deletions
+13
View File
@@ -31,6 +31,19 @@
/> />
<div><span id="compute-interval-value">100</span> ms</div> <div><span id="compute-interval-value">100</span> ms</div>
</label> </label>
<div>
<label for="grid-size-slider">Grid Size</label>
<input
type="range"
id="grid-size-slider"
min="16"
max="512"
step="16"
value="64"
/>
<span id="grid-size-value">64</span>
</div>
<button id="reset-button">Reset Grid</button> <button id="reset-button">Reset Grid</button>
</div> </div>
</div> </div>
+51 -10
View File
@@ -1,6 +1,6 @@
import "./style.css" import "./style.css"
const GRID_SIZE = 64 let GRID_SIZE = 64
let COMPUTE_MS_INTERVAL = 100 let COMPUTE_MS_INTERVAL = 100
class UIController { class UIController {
@@ -21,6 +21,21 @@ class UIController {
valueLabel.textContent = slider.value valueLabel.textContent = slider.value
}) })
} }
static onGridSizeChange(callback: (size: number) => void) {
const slider = document.getElementById(
"grid-size-slider",
) as HTMLInputElement
const valueLabel = document.getElementById("grid-size-value") as HTMLElement
let timeout: ReturnType<typeof setTimeout>
slider.addEventListener("input", () => {
clearTimeout(timeout)
const size = parseInt(slider.value)
valueLabel.textContent = slider.value
timeout = setTimeout(() => callback(size), 150)
})
}
} }
async function getCanvas(): Promise<HTMLCanvasElement> { async function getCanvas(): Promise<HTMLCanvasElement> {
@@ -287,19 +302,45 @@ class Renderer {
} }
class Engine { class Engine {
private simulation!: Simulation
private renderer!: Renderer
private animationFrameId: number | null = null
async start() { async start() {
UIController.setup() UIController.setup()
const device = await getDevice() const device = await getDevice()
const canvas = await getCanvas() const canvas = await getCanvas()
const context = canvas.getContext("webgpu")! const context = canvas.getContext("webgpu")!
const format = navigator.gpu.getPreferredCanvasFormat() const format = navigator.gpu.getPreferredCanvasFormat()
context.configure({ device, format }) context.configure({ device, format })
const grid = new Grid(GRID_SIZE, device) this.init(device, context, format, GRID_SIZE)
UIController.onReset(() => this.simulation.reset(GRID_SIZE))
UIController.onGridSizeChange((newSize) => {
this.stopRendering()
GRID_SIZE = newSize
this.init(device, context, format, newSize)
})
}
private stopRendering() {
if (this.animationFrameId !== null) {
cancelAnimationFrame(this.animationFrameId)
this.animationFrameId = null
}
}
private async init(
device: GPUDevice,
context: GPUCanvasContext,
format: GPUTextureFormat,
gridSize: number,
) {
const grid = new Grid(gridSize, device)
const timeBuffer = Buffers.createTimeBuffer(device) const timeBuffer = Buffers.createTimeBuffer(device)
const [vertexBuffer, vertices] = Buffers.createVertexBuffer(device) const [vertexBuffer, vertices] = Buffers.createVertexBuffer(device)
const stateBuffers = Buffers.createStateBuffers(device, GRID_SIZE) const stateBuffers = Buffers.createStateBuffers(device, gridSize)
const layout = PipelineFactory.createBindGroupLayout(device) const layout = PipelineFactory.createBindGroupLayout(device)
const pipelineLayout = PipelineFactory.createPipelineLayout(device, layout) const pipelineLayout = PipelineFactory.createPipelineLayout(device, layout)
@@ -308,27 +349,27 @@ class Engine {
PipelineFactory.createCompute(device, pipelineLayout), PipelineFactory.createCompute(device, pipelineLayout),
]) ])
const simulation = new Simulation( this.simulation = new Simulation(
device, device,
grid, grid,
timeBuffer, timeBuffer,
stateBuffers, stateBuffers,
layout, layout,
) )
const renderer = new Renderer( this.renderer = new Renderer(
device, device,
context, context,
renderPipeline, renderPipeline,
computePipeline, computePipeline,
vertexBuffer, vertexBuffer,
vertices, vertices,
simulation, this.simulation,
timeBuffer, timeBuffer,
) )
UIController.onReset(() => simulation.reset(GRID_SIZE)) this.animationFrameId = requestAnimationFrame(
this.renderer.render.bind(this.renderer),
requestAnimationFrame(renderer.render.bind(renderer)) )
} }
} }