Files
webeditor3d/src/core/terrain-brush.ts
Victor Giers e9adf9f37e auto-git:
[change] src/commands/apply-terrain-brush-patch-command.ts
 [change] src/core/terrain-brush.ts
 [change] src/document/migrate-scene-document.ts
 [change] src/document/scene-document.ts
 [change] src/geometry/terrain-brush.ts
 [change] src/geometry/terrain-mesh.ts
2026-05-02 11:25:15 +02:00

169 lines
4.2 KiB
TypeScript

import { TERRAIN_LAYER_COUNT } from "../document/terrains";
export type TerrainBrushTool =
| "raise"
| "lower"
| "smooth"
| "flatten"
| "paint"
| "foliagePaint"
| "foliageErase"
| "foliageBlockerPaint"
| "foliageBlockerErase";
export interface TerrainBrushSettings {
radius: number;
strength: number;
falloff: number;
}
export interface ArmedTerrainSculptBrushState extends TerrainBrushSettings {
terrainId: string;
tool: Exclude<
TerrainBrushTool,
"paint" | "foliagePaint" | "foliageErase" | "foliageBlockerPaint" | "foliageBlockerErase"
>;
}
export interface ArmedTerrainPaintBrushState extends TerrainBrushSettings {
terrainId: string;
tool: "paint";
layerIndex: number;
}
export interface ArmedTerrainFoliagePaintBrushState
extends TerrainBrushSettings {
terrainId: string;
tool: "foliagePaint" | "foliageErase";
foliageLayerId: string;
}
export interface ArmedTerrainFoliageBlockerBrushState
extends TerrainBrushSettings {
terrainId: string;
tool: "foliageBlockerPaint" | "foliageBlockerErase";
}
export type ArmedTerrainBrushState =
| ArmedTerrainSculptBrushState
| ArmedTerrainPaintBrushState
| ArmedTerrainFoliagePaintBrushState
| ArmedTerrainFoliageBlockerBrushState;
export interface TerrainSampleValuePatch {
index: number;
before: number;
after: number;
}
export interface TerrainFoliageMaskValuePatch extends TerrainSampleValuePatch {
layerId: string;
}
export interface TerrainBrushPatch {
terrainId: string;
heightSamples: TerrainSampleValuePatch[];
paintWeights: TerrainSampleValuePatch[];
foliageMaskValues: TerrainFoliageMaskValuePatch[];
foliageBlockerMaskValues: TerrainSampleValuePatch[];
}
export interface TerrainBrushStrokeCommit {
terrainId: string;
patch: TerrainBrushPatch;
commandLabel: string;
tool: TerrainBrushTool;
}
export const DEFAULT_TERRAIN_BRUSH_RADIUS = 2;
export const DEFAULT_TERRAIN_BRUSH_STRENGTH = 0.35;
export const DEFAULT_TERRAIN_BRUSH_FALLOFF = 0.6;
export const MIN_TERRAIN_BRUSH_RADIUS = 0.25;
export const MAX_TERRAIN_BRUSH_RADIUS = 12;
export const MIN_TERRAIN_BRUSH_STRENGTH = 0.05;
export const MAX_TERRAIN_BRUSH_STRENGTH = 1;
export const MIN_TERRAIN_BRUSH_FALLOFF = 0;
export const MAX_TERRAIN_BRUSH_FALLOFF = 1;
function clamp(value: number, min: number, max: number): number {
return Math.min(max, Math.max(min, value));
}
export function clampTerrainBrushRadius(radius: number): number {
if (!Number.isFinite(radius)) {
return DEFAULT_TERRAIN_BRUSH_RADIUS;
}
return clamp(radius, MIN_TERRAIN_BRUSH_RADIUS, MAX_TERRAIN_BRUSH_RADIUS);
}
export function clampTerrainBrushStrength(strength: number): number {
if (!Number.isFinite(strength)) {
return DEFAULT_TERRAIN_BRUSH_STRENGTH;
}
return clamp(
strength,
MIN_TERRAIN_BRUSH_STRENGTH,
MAX_TERRAIN_BRUSH_STRENGTH
);
}
export function clampTerrainBrushFalloff(falloff: number): number {
if (!Number.isFinite(falloff)) {
return DEFAULT_TERRAIN_BRUSH_FALLOFF;
}
return clamp(
falloff,
MIN_TERRAIN_BRUSH_FALLOFF,
MAX_TERRAIN_BRUSH_FALLOFF
);
}
export function createDefaultTerrainBrushSettings(): TerrainBrushSettings {
return {
radius: DEFAULT_TERRAIN_BRUSH_RADIUS,
strength: DEFAULT_TERRAIN_BRUSH_STRENGTH,
falloff: DEFAULT_TERRAIN_BRUSH_FALLOFF
};
}
export function clampTerrainPaintLayerIndex(layerIndex: number): number {
if (!Number.isFinite(layerIndex)) {
return 0;
}
return Math.min(
TERRAIN_LAYER_COUNT - 1,
Math.max(0, Math.round(layerIndex))
);
}
export function getTerrainBrushToolLabel(tool: TerrainBrushTool): string {
switch (tool) {
case "raise":
return "Raise";
case "lower":
return "Lower";
case "smooth":
return "Smooth";
case "flatten":
return "Flatten";
case "paint":
return "Paint";
case "foliagePaint":
return "Paint Foliage";
case "foliageErase":
return "Erase Foliage";
case "foliageBlockerPaint":
return "Paint Foliage Blocker";
case "foliageBlockerErase":
return "Clear Foliage Blocker";
}
}
export function getTerrainBrushCommandLabel(tool: TerrainBrushTool): string {
return `${getTerrainBrushToolLabel(tool)} terrain`;
}