Enable material paint for fence slab and ceiling nodes

This commit is contained in:
sudhir
2026-04-21 15:19:46 +05:30
parent b925cf1e7a
commit 65399731f7
3 changed files with 97 additions and 3 deletions
@@ -2,13 +2,16 @@ import {
type AnyNode, type AnyNode,
type AnyNodeId, type AnyNodeId,
type BuildingNode, type BuildingNode,
type CeilingNode,
emitter, emitter,
type FenceNode,
type ItemNode, type ItemNode,
type NodeEvent, type NodeEvent,
type RoofEvent, type RoofEvent,
type RoofNode, type RoofNode,
type RoofSegmentEvent, type RoofSegmentEvent,
resolveLevelId, resolveLevelId,
type SlabNode,
type StairEvent, type StairEvent,
type StairNode, type StairNode,
type StairSegmentEvent, type StairSegmentEvent,
@@ -25,6 +28,7 @@ import { useCallback, useEffect, useRef } from 'react'
import { type BufferGeometry, Color, type Material, type Mesh, type Object3D } from 'three' import { type BufferGeometry, Color, type Material, type Mesh, type Object3D } from 'three'
import { import {
buildRoofSurfaceMaterialPatch, buildRoofSurfaceMaterialPatch,
buildSingleSurfaceMaterialPatch,
buildStairSurfaceMaterialPatch, buildStairSurfaceMaterialPatch,
buildWallSurfaceMaterialPatch, buildWallSurfaceMaterialPatch,
hasActivePaintMaterial, hasActivePaintMaterial,
@@ -609,7 +613,30 @@ export const SelectionManager = () => {
} }
} }
const disabledNodeTypes = ['fence', 'item', 'slab', 'ceiling', 'window', 'door', 'zone'] if (node.type === 'fence' || node.type === 'slab' || node.type === 'ceiling') {
const target = node.type
const compatible =
isActivePaintMaterialCompatible(activePaintMaterial, target) &&
hasActivePaintMaterial(activePaintMaterial)
return {
apply: compatible
? () => {
useScene
.getState()
.updateNode(
node.id as AnyNodeId,
buildSingleSurfaceMaterialPatch<FenceNode | SlabNode | CeilingNode>(
activePaintMaterial.material,
activePaintMaterial.materialPreset,
),
)
}
: null,
}
}
const disabledNodeTypes = ['item', 'window', 'door', 'zone']
if (disabledNodeTypes.includes(node.type)) { if (disabledNodeTypes.includes(node.type)) {
return { return {
apply: null, apply: null,
@@ -776,6 +803,14 @@ export const SelectionManager = () => {
nextMaterialTargetHandled = true nextMaterialTargetHandled = true
} }
if (
(node.type === 'fence' || node.type === 'slab' || node.type === 'ceiling') &&
nodeToSelect.type === node.type
) {
setSelectedMaterialTargetForNode(nodeToSelect, 'surface')
nextMaterialTargetHandled = true
}
if (!nextMaterialTargetHandled && useEditor.getState().selectedMaterialTarget) { if (!nextMaterialTargetHandled && useEditor.getState().selectedMaterialTarget) {
useEditor.getState().setSelectedMaterialTarget(null) useEditor.getState().setSelectedMaterialTarget(null)
} }
@@ -1092,6 +1127,9 @@ const SelectionStateSync = () => {
if ( if (
!selectedNode || !selectedNode ||
(selectedNode.type !== 'wall' && (selectedNode.type !== 'wall' &&
selectedNode.type !== 'fence' &&
selectedNode.type !== 'slab' &&
selectedNode.type !== 'ceiling' &&
selectedNode.type !== 'stair' && selectedNode.type !== 'stair' &&
selectedNode.type !== 'roof') selectedNode.type !== 'roof')
) { ) {
+56 -2
View File
@@ -1,6 +1,8 @@
'use client' 'use client'
import { import {
type CeilingNode,
type FenceNode,
getCatalogMaterialById, getCatalogMaterialById,
getEffectiveRoofSurfaceMaterial, getEffectiveRoofSurfaceMaterial,
getEffectiveStairSurfaceMaterial, getEffectiveStairSurfaceMaterial,
@@ -10,13 +12,19 @@ import {
type MaterialTarget, type MaterialTarget,
type RoofNode, type RoofNode,
type RoofSurfaceMaterialRole, type RoofSurfaceMaterialRole,
type SlabNode,
type StairNode, type StairNode,
type StairSurfaceMaterialRole, type StairSurfaceMaterialRole,
type WallNode, type WallNode,
type WallSurfaceSide, type WallSurfaceSide,
} from '@pascal-app/core' } from '@pascal-app/core'
export type PaintableMaterialTarget = Extract<MaterialTarget, 'wall' | 'roof' | 'stair'> export type PaintableMaterialTarget = Extract<
MaterialTarget,
'wall' | 'roof' | 'stair' | 'fence' | 'slab' | 'ceiling'
>
export type SingleSurfaceMaterialRole = 'surface'
export type ActivePaintMaterial = { export type ActivePaintMaterial = {
material?: MaterialSchema material?: MaterialSchema
@@ -135,12 +143,26 @@ export function buildStairSurfaceMaterialPatch(
} }
} }
export function buildSingleSurfaceMaterialPatch<TNode extends FenceNode | SlabNode | CeilingNode>(
material: MaterialSchema | undefined,
materialPreset: string | undefined,
): Partial<TNode> {
return {
material,
materialPreset,
} as Partial<TNode>
}
export function resolveActivePaintMaterialFromSelection(params: { export function resolveActivePaintMaterialFromSelection(params: {
nodes: Record<string, any> nodes: Record<string, any>
selectedId: string | null selectedId: string | null
selectedMaterialTarget: { selectedMaterialTarget: {
nodeId: string nodeId: string
role: WallSurfaceSide | StairSurfaceMaterialRole | RoofSurfaceMaterialRole role:
| WallSurfaceSide
| StairSurfaceMaterialRole
| RoofSurfaceMaterialRole
| SingleSurfaceMaterialRole
} | null } | null
}): ActivePaintMaterial | null { }): ActivePaintMaterial | null {
const { nodes, selectedId, selectedMaterialTarget } = params const { nodes, selectedId, selectedMaterialTarget } = params
@@ -208,6 +230,26 @@ export function resolveActivePaintMaterialFromSelection(params: {
: null : null
} }
if (
(selectedNode.type === 'fence' ||
selectedNode.type === 'slab' ||
selectedNode.type === 'ceiling') &&
selectedMaterialTarget.role === 'surface'
) {
const target = selectedNode.type
return hasActivePaintMaterial({
material: selectedNode.material,
materialPreset: selectedNode.materialPreset,
sourceTarget: target,
})
? {
material: selectedNode.material,
materialPreset: selectedNode.materialPreset,
sourceTarget: target,
}
: null
}
return null return null
} }
@@ -233,5 +275,17 @@ export function resolvePaintTargetFromSelection(params: {
return 'stair' return 'stair'
} }
if (selectedNode.type === 'fence') {
return 'fence'
}
if (selectedNode.type === 'slab') {
return 'slab'
}
if (selectedNode.type === 'ceiling') {
return 'ceiling'
}
return null return null
} }
+2
View File
@@ -31,6 +31,7 @@ import {
type PaintableMaterialTarget, type PaintableMaterialTarget,
resolveActivePaintMaterialFromSelection, resolveActivePaintMaterialFromSelection,
resolvePaintTargetFromSelection, resolvePaintTargetFromSelection,
type SingleSurfaceMaterialRole,
} from '../lib/material-paint' } from '../lib/material-paint'
const DEFAULT_ACTIVE_SIDEBAR_PANEL = 'site' const DEFAULT_ACTIVE_SIDEBAR_PANEL = 'site'
@@ -94,6 +95,7 @@ export type MaterialTargetRole =
| WallSurfaceSide | WallSurfaceSide
| StairSurfaceMaterialRole | StairSurfaceMaterialRole
| RoofSurfaceMaterialRole | RoofSurfaceMaterialRole
| SingleSurfaceMaterialRole
export type SelectedMaterialTarget = { export type SelectedMaterialTarget = {
nodeId: AnyNodeId nodeId: AnyNodeId