diff --git a/src/Config.ts b/src/Config.ts index 93d1513..6f48bab 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -13,6 +13,7 @@ const defaults = { antSpeed: 1, antRotationAngle: Math.PI / 30, brushRadius: 20, + brushMaterial: -1, cameraZoom: 0, gravityDirection: "down" as const, viewMode: "side" as "side" | "top", diff --git a/src/GUI.ts b/src/GUI.ts index 7a81359..7ae8f31 100644 --- a/src/GUI.ts +++ b/src/GUI.ts @@ -1,5 +1,13 @@ import GUI from "lil-gui"; import Config, { resetConfig, saveConfig } from "./Config"; +import { + MAT_AIR, + MAT_DIRT, + MAT_FOOD, + MAT_HOME, + MAT_ROCK, + MAT_SAND, +} from "./constants"; type EventHandler = () => void; @@ -40,10 +48,6 @@ class GUIController { const controlsFolder = this.gui.addFolder("Controls"); - controlsFolder - .add(Config, "brushRadius", 1, 100) - .name("Brush radius") - .onChange(() => saveConfig()); controlsFolder .add(Config, "cameraZoom") .name("Zoom") @@ -56,6 +60,43 @@ class GUIController { .listen() .onChange(() => this.saveAndEmit("reset")); + // brush material labels map to material IDs + const brushLabels: Record = { + "none (–)": -1, + "air (R)": MAT_AIR, + "sand (1)": MAT_SAND, + "dirt (2)": MAT_DIRT, + "rock (E)": MAT_ROCK, + "food (W)": MAT_FOOD, + "home (Q)": MAT_HOME, + }; + + // proxy object for lil-gui string dropdown — initialize from saved config + const savedBrushLabel = + Object.entries(brushLabels).find( + ([, id]) => id === Config.brushMaterial, + )?.[0] ?? "none (–)"; + const brushProxy = { + material: savedBrushLabel, + }; + + const brushFolder = this.gui.addFolder("Brush"); + + brushFolder + .add(brushProxy, "material", Object.keys(brushLabels)) + .name("Material") + .onChange((label: string) => { + Config.brushMaterial = brushLabels[label] ?? -1; + saveConfig(); + }); + + brushFolder + .add(Config, "brushRadius", 1, 100) + .name("Radius") + .onChange(() => saveConfig()); + + brushFolder.open(); + simFolder.open(); controlsFolder.open(); diff --git a/src/Renderer.ts b/src/Renderer.ts index 54dbce2..d1b0d54 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -248,7 +248,8 @@ export default class Renderer { this.resources.worldRenderTarget.texture; scenes.draw.material.uniforms.pointerPosition.value = scenes.screen.pointerPosition; - scenes.draw.material.uniforms.drawMode.value = scenes.screen.drawMode; + scenes.draw.material.uniforms.drawMode.value = + scenes.screen.effectiveDrawMode; scenes.draw.material.uniforms.brushRadius.value = Config.brushRadius; this.renderer.render(scenes.draw, scenes.draw.camera); this.renderer.copyFramebufferToTexture( diff --git a/src/scenes/ScreenScene.ts b/src/scenes/ScreenScene.ts index d2dc4b4..4254cdb 100644 --- a/src/scenes/ScreenScene.ts +++ b/src/scenes/ScreenScene.ts @@ -24,6 +24,14 @@ export default class ScreenScene extends AbstractScene { public drawMode: number = -1; // zoom stored in Config.cameraZoom private isPointerDown: boolean = false; + + // resolves active draw mode: key-held takes priority, then GUI brush selection + public get effectiveDrawMode(): number { + if (this.drawMode >= 0) return this.drawMode; + if (this.isPointerDown && Config.brushMaterial >= 0) + return Config.brushMaterial; + return -1; + } public renderWidth: number = 1; public renderHeight: number = 1;