Add box brush mesh and update related files

This commit is contained in:
2026-04-15 07:43:30 +02:00
parent bf662f76f2
commit d80b32408d
11 changed files with 880 additions and 135 deletions

View File

@@ -1,25 +1,25 @@
import { cloneEditorSelection, type EditorSelection } from "../core/selection";
import {
cloneBrush,
cloneBrushGeometry,
cloneFaceUvState,
type BoxBrush,
type BoxEdgeId,
type BoxFaceId,
type BoxVertexId,
type Brush,
type BrushFace
} from "../document/brushes";
import type { SceneDocument } from "../document/scene-document";
import type {
WhiteboxEdgeId,
WhiteboxFaceId,
WhiteboxVertexId
} from "../document/brushes";
export function getBoxBrushOrThrow(document: SceneDocument, brushId: string): BoxBrush {
export function getBoxBrushOrThrow(document: SceneDocument, brushId: string): Brush {
const brush = document.brushes[brushId];
if (brush === undefined) {
throw new Error(`Box brush ${brushId} does not exist.`);
}
if (brush.kind !== "box") {
throw new Error(`Brush ${brushId} is not a supported box brush.`);
}
return brush;
}
@@ -30,7 +30,7 @@ export function setSingleBrushSelection(brushId: string): EditorSelection {
};
}
export function setSingleBrushFaceSelection(brushId: string, faceId: BoxFaceId): EditorSelection {
export function setSingleBrushFaceSelection(brushId: string, faceId: WhiteboxFaceId): EditorSelection {
return {
kind: "brushFace",
brushId,
@@ -38,7 +38,7 @@ export function setSingleBrushFaceSelection(brushId: string, faceId: BoxFaceId):
};
}
export function setSingleBrushEdgeSelection(brushId: string, edgeId: BoxEdgeId): EditorSelection {
export function setSingleBrushEdgeSelection(brushId: string, edgeId: WhiteboxEdgeId): EditorSelection {
return {
kind: "brushEdge",
brushId,
@@ -46,7 +46,7 @@ export function setSingleBrushEdgeSelection(brushId: string, edgeId: BoxEdgeId):
};
}
export function setSingleBrushVertexSelection(brushId: string, vertexId: BoxVertexId): EditorSelection {
export function setSingleBrushVertexSelection(brushId: string, vertexId: WhiteboxVertexId): EditorSelection {
return {
kind: "brushVertex",
brushId,
@@ -58,12 +58,12 @@ export function cloneSelectionForCommand(selection: EditorSelection): EditorSele
return cloneEditorSelection(selection);
}
export function replaceBrush(document: SceneDocument, brush: BoxBrush): SceneDocument {
export function replaceBrush(document: SceneDocument, brush: Brush): SceneDocument {
return {
...document,
brushes: {
...document.brushes,
[brush.id]: brush
[brush.id]: cloneBrush(brush)
}
};
}
@@ -80,7 +80,7 @@ export function removeBrush(document: SceneDocument, brushId: string): SceneDocu
};
}
export function getBoxBrushFaceOrThrow(document: SceneDocument, brushId: string, faceId: BoxFaceId): BrushFace {
export function getBoxBrushFaceOrThrow(document: SceneDocument, brushId: string, faceId: WhiteboxFaceId): BrushFace {
const brush = getBoxBrushOrThrow(document, brushId);
const face = brush.faces[faceId];
@@ -91,7 +91,7 @@ export function getBoxBrushFaceOrThrow(document: SceneDocument, brushId: string,
return face;
}
export function replaceBoxBrushFace(document: SceneDocument, brushId: string, faceId: BoxFaceId, face: BrushFace): SceneDocument {
export function replaceBoxBrushFace(document: SceneDocument, brushId: string, faceId: WhiteboxFaceId, face: BrushFace): SceneDocument {
const brush = getBoxBrushOrThrow(document, brushId);
return replaceBrush(document, {
@@ -102,6 +102,7 @@ export function replaceBoxBrushFace(document: SceneDocument, brushId: string, fa
materialId: face.materialId,
uv: cloneFaceUvState(face.uv)
}
}
},
geometry: cloneBrushGeometry(brush.geometry)
});
}

View File

@@ -1,7 +1,8 @@
import type { ToolMode } from "../core/tool-mode";
import { createOpaqueId } from "../core/ids";
import type { EditorSelection } from "../core/selection";
import { BOX_FACE_IDS, type BoxFaceId } from "../document/brushes";
import type { WhiteboxFaceId } from "../document/brushes";
import { getBrushFaceIds } from "../geometry/whitebox-topology";
import {
cloneSelectionForCommand,
@@ -18,7 +19,7 @@ interface SetBoxBrushAllFaceMaterialsCommandOptions {
export function createSetBoxBrushAllFaceMaterialsCommand(
options: SetBoxBrushAllFaceMaterialsCommandOptions
): EditorCommand {
let previousMaterialIds: Record<BoxFaceId, string | null> | null = null;
let previousMaterialIds: Record<WhiteboxFaceId, string | null> | null = null;
let previousSelection: EditorSelection | null = null;
let previousToolMode: ToolMode | null = null;
@@ -42,14 +43,12 @@ export function createSetBoxBrushAllFaceMaterialsCommand(
}
if (previousMaterialIds === null) {
previousMaterialIds = {
posX: currentBrush.faces.posX.materialId,
negX: currentBrush.faces.negX.materialId,
posY: currentBrush.faces.posY.materialId,
negY: currentBrush.faces.negY.materialId,
posZ: currentBrush.faces.posZ.materialId,
negZ: currentBrush.faces.negZ.materialId
};
previousMaterialIds = Object.fromEntries(
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
currentBrush.faces[faceId].materialId
])
);
}
if (previousSelection === null) {
@@ -64,7 +63,7 @@ export function createSetBoxBrushAllFaceMaterialsCommand(
replaceBrush(currentDocument, {
...currentBrush,
faces: Object.fromEntries(
BOX_FACE_IDS.map((faceId) => [
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
{
...currentBrush.faces[faceId],
@@ -87,32 +86,15 @@ export function createSetBoxBrushAllFaceMaterialsCommand(
context.setDocument(
replaceBrush(currentDocument, {
...currentBrush,
faces: {
posX: {
...currentBrush.faces.posX,
materialId: previousMaterialIds.posX
},
negX: {
...currentBrush.faces.negX,
materialId: previousMaterialIds.negX
},
posY: {
...currentBrush.faces.posY,
materialId: previousMaterialIds.posY
},
negY: {
...currentBrush.faces.negY,
materialId: previousMaterialIds.negY
},
posZ: {
...currentBrush.faces.posZ,
materialId: previousMaterialIds.posZ
},
negZ: {
...currentBrush.faces.negZ,
materialId: previousMaterialIds.negZ
}
}
faces: Object.fromEntries(
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
{
...currentBrush.faces[faceId],
materialId: previousMaterialIds[faceId] ?? null
}
])
) as typeof currentBrush.faces
})
);

View File

@@ -1,7 +1,7 @@
import type { ToolMode } from "../core/tool-mode";
import { createOpaqueId } from "../core/ids";
import type { EditorSelection } from "../core/selection";
import type { BoxFaceId } from "../document/brushes";
import type { WhiteboxFaceId } from "../document/brushes";
import {
cloneSelectionForCommand,
@@ -13,7 +13,7 @@ import type { EditorCommand } from "./command";
interface SetBoxBrushFaceMaterialCommandOptions {
brushId: string;
faceId: BoxFaceId;
faceId: WhiteboxFaceId;
materialId: string | null;
}

View File

@@ -1,7 +1,11 @@
import type { ToolMode } from "../core/tool-mode";
import { createOpaqueId } from "../core/ids";
import type { EditorSelection } from "../core/selection";
import { cloneFaceUvState, type BoxFaceId, type FaceUvState } from "../document/brushes";
import {
cloneFaceUvState,
type FaceUvState,
type WhiteboxFaceId
} from "../document/brushes";
import {
cloneSelectionForCommand,
@@ -13,7 +17,7 @@ import type { EditorCommand } from "./command";
interface SetBoxBrushFaceUvStateCommandOptions {
brushId: string;
faceId: BoxFaceId;
faceId: WhiteboxFaceId;
uvState: FaceUvState;
label?: string;
}

View File

@@ -2,11 +2,11 @@ import type { ToolMode } from "../core/tool-mode";
import { createOpaqueId } from "../core/ids";
import type { EditorSelection } from "../core/selection";
import {
BOX_FACE_IDS,
cloneFaceUvState,
type BoxFaceId,
type FaceUvState
type FaceUvState,
type WhiteboxFaceId
} from "../document/brushes";
import { getBrushFaceIds } from "../geometry/whitebox-topology";
import {
cloneSelectionForCommand,
@@ -18,13 +18,13 @@ import type { EditorCommand } from "./command";
interface UpdateBoxBrushAllFaceUvsCommandOptions {
brushId: string;
label: string;
updateUvState(uvState: FaceUvState, faceId: BoxFaceId): FaceUvState;
updateUvState(uvState: FaceUvState, faceId: WhiteboxFaceId): FaceUvState;
}
export function createUpdateBoxBrushAllFaceUvsCommand(
options: UpdateBoxBrushAllFaceUvsCommandOptions
): EditorCommand {
let previousUvStates: Record<BoxFaceId, FaceUvState> | null = null;
let previousUvStates: Record<WhiteboxFaceId, FaceUvState> | null = null;
let previousSelection: EditorSelection | null = null;
let previousToolMode: ToolMode | null = null;
@@ -36,14 +36,12 @@ export function createUpdateBoxBrushAllFaceUvsCommand(
const currentBrush = getBoxBrushOrThrow(currentDocument, options.brushId);
if (previousUvStates === null) {
previousUvStates = {
posX: cloneFaceUvState(currentBrush.faces.posX.uv),
negX: cloneFaceUvState(currentBrush.faces.negX.uv),
posY: cloneFaceUvState(currentBrush.faces.posY.uv),
negY: cloneFaceUvState(currentBrush.faces.negY.uv),
posZ: cloneFaceUvState(currentBrush.faces.posZ.uv),
negZ: cloneFaceUvState(currentBrush.faces.negZ.uv)
};
previousUvStates = Object.fromEntries(
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
cloneFaceUvState(currentBrush.faces[faceId].uv)
])
);
}
if (previousSelection === null) {
@@ -58,7 +56,7 @@ export function createUpdateBoxBrushAllFaceUvsCommand(
replaceBrush(currentDocument, {
...currentBrush,
faces: Object.fromEntries(
BOX_FACE_IDS.map((faceId) => [
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
{
...currentBrush.faces[faceId],
@@ -83,32 +81,15 @@ export function createUpdateBoxBrushAllFaceUvsCommand(
context.setDocument(
replaceBrush(currentDocument, {
...currentBrush,
faces: {
posX: {
...currentBrush.faces.posX,
uv: cloneFaceUvState(previousUvStates.posX)
},
negX: {
...currentBrush.faces.negX,
uv: cloneFaceUvState(previousUvStates.negX)
},
posY: {
...currentBrush.faces.posY,
uv: cloneFaceUvState(previousUvStates.posY)
},
negY: {
...currentBrush.faces.negY,
uv: cloneFaceUvState(previousUvStates.negY)
},
posZ: {
...currentBrush.faces.posZ,
uv: cloneFaceUvState(previousUvStates.posZ)
},
negZ: {
...currentBrush.faces.negZ,
uv: cloneFaceUvState(previousUvStates.negZ)
}
}
faces: Object.fromEntries(
getBrushFaceIds(currentBrush).map((faceId) => [
faceId,
{
...currentBrush.faces[faceId],
uv: cloneFaceUvState(previousUvStates[faceId])
}
])
) as typeof currentBrush.faces
})
);