Fix slab material reload and wall curve step
This commit is contained in:
@@ -21,6 +21,20 @@ function stepPrecision(s: number): number {
|
||||
return Math.max(0, Math.ceil(-Math.log10(s)))
|
||||
}
|
||||
|
||||
function getAdjustedStep(
|
||||
baseStep: number,
|
||||
modifiers: {
|
||||
shiftKey?: boolean
|
||||
metaKey?: boolean
|
||||
ctrlKey?: boolean
|
||||
altKey?: boolean
|
||||
},
|
||||
): number {
|
||||
if (modifiers.shiftKey) return baseStep * 10
|
||||
if (modifiers.metaKey || modifiers.ctrlKey || modifiers.altKey) return baseStep * 0.1
|
||||
return baseStep
|
||||
}
|
||||
|
||||
export function SliderControl({
|
||||
label,
|
||||
value,
|
||||
@@ -58,16 +72,14 @@ export function SliderControl({
|
||||
if (isEditing) return
|
||||
e.preventDefault()
|
||||
const direction = e.deltaY < 0 ? 1 : -1
|
||||
let s = step
|
||||
if (e.shiftKey) s = step * 10
|
||||
else if (e.altKey) s = step * 0.1
|
||||
const s = getAdjustedStep(step, e)
|
||||
const newValue = clamp(valueRef.current + direction * s)
|
||||
const final = Number.parseFloat(newValue.toFixed(stepPrecision(s)))
|
||||
if (final !== valueRef.current) onChange(final)
|
||||
}
|
||||
el.addEventListener('wheel', handleWheel, { passive: false })
|
||||
return () => el.removeEventListener('wheel', handleWheel)
|
||||
}, [isEditing, step, clamp, onChange, precision])
|
||||
}, [isEditing, step, clamp, onChange])
|
||||
|
||||
// Arrow key support while hovered
|
||||
useEffect(() => {
|
||||
@@ -78,9 +90,7 @@ export function SliderControl({
|
||||
else if (e.key === 'ArrowDown' || e.key === 'ArrowLeft') direction = -1
|
||||
if (direction !== 0) {
|
||||
e.preventDefault()
|
||||
let s = step
|
||||
if (e.shiftKey) s = step * 10
|
||||
else if (e.metaKey || e.ctrlKey) s = step * 0.1
|
||||
const s = getAdjustedStep(step, e)
|
||||
const newValue = clamp(valueRef.current + direction * s)
|
||||
const final = Number.parseFloat(newValue.toFixed(stepPrecision(s)))
|
||||
if (final !== valueRef.current) onChange(final)
|
||||
@@ -88,7 +98,7 @@ export function SliderControl({
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [isHovered, isEditing, step, clamp, onChange, precision])
|
||||
}, [isHovered, isEditing, step, clamp, onChange])
|
||||
|
||||
const handleLabelPointerDown = useCallback(
|
||||
(e: React.PointerEvent<HTMLDivElement>) => {
|
||||
@@ -107,16 +117,14 @@ export function SliderControl({
|
||||
if (!dragRef.current) return
|
||||
const { startX, startValue } = dragRef.current
|
||||
const dx = e.clientX - startX
|
||||
let s = step
|
||||
if (e.shiftKey) s = step * 10
|
||||
else if (e.metaKey || e.ctrlKey) s = step * 0.1
|
||||
const s = getAdjustedStep(step, e)
|
||||
// 4 px per step at default sensitivity
|
||||
const newValue = clamp(
|
||||
Number.parseFloat((startValue + (dx / 4) * s).toFixed(stepPrecision(s))),
|
||||
)
|
||||
onChange(newValue)
|
||||
},
|
||||
[step, precision, clamp, onChange],
|
||||
[step, clamp, onChange],
|
||||
)
|
||||
|
||||
const handleLabelPointerUp = useCallback(
|
||||
@@ -163,12 +171,18 @@ export function SliderControl({
|
||||
setIsEditing(false)
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault()
|
||||
const newV = clamp(value + step)
|
||||
const adjustedStep = getAdjustedStep(step, e)
|
||||
const newV = clamp(
|
||||
Number.parseFloat((value + adjustedStep).toFixed(stepPrecision(adjustedStep))),
|
||||
)
|
||||
onChange(newV)
|
||||
setInputValue(newV.toFixed(precision))
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
e.preventDefault()
|
||||
const newV = clamp(value - step)
|
||||
const adjustedStep = getAdjustedStep(step, e)
|
||||
const newV = clamp(
|
||||
Number.parseFloat((value - adjustedStep).toFixed(stepPrecision(adjustedStep))),
|
||||
)
|
||||
onChange(newV)
|
||||
setInputValue(newV.toFixed(precision))
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ export function WallPanel() {
|
||||
min={-Math.max(0.01, maxCurveOffset)}
|
||||
onChange={(v) => handleUpdate({ curveOffset: normalizeWallCurveOffset(node, v) })}
|
||||
precision={2}
|
||||
step={0.01}
|
||||
step={0.1}
|
||||
unit="m"
|
||||
value={Math.round(curveOffset * 100) / 100}
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { type SlabNode, useRegistry } from '@pascal-app/core'
|
||||
import { getMaterialPresetByRef, type SlabNode, useRegistry } from '@pascal-app/core'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import * as THREE from 'three'
|
||||
import type { Mesh } from 'three'
|
||||
import { useNodeEvents } from '../../../hooks/use-node-events'
|
||||
import {
|
||||
applyMaterialPresetToMaterials,
|
||||
createMaterial,
|
||||
createMaterialFromPresetRef,
|
||||
DEFAULT_SLAB_MATERIAL,
|
||||
} from '../../../lib/materials'
|
||||
|
||||
@@ -17,9 +17,18 @@ export const SlabRenderer = ({ node }: { node: SlabNode }) => {
|
||||
const handlers = useNodeEvents(node, 'slab')
|
||||
|
||||
const material = useMemo(() => {
|
||||
const presetMaterial = createMaterialFromPresetRef(node.materialPreset)
|
||||
const sourceMaterial = presetMaterial ?? (node.material ? createMaterial(node.material) : DEFAULT_SLAB_MATERIAL)
|
||||
const slabMaterial = sourceMaterial.clone()
|
||||
const preset = getMaterialPresetByRef(node.materialPreset)
|
||||
const slabMaterial = preset
|
||||
? new THREE.MeshStandardMaterial()
|
||||
: node.material
|
||||
? createMaterial(node.material).clone()
|
||||
: DEFAULT_SLAB_MATERIAL.clone()
|
||||
|
||||
if (preset) {
|
||||
// Apply the preset to the slab-owned material so async texture loads update
|
||||
// the instance we actually render after refresh as well.
|
||||
applyMaterialPresetToMaterials(slabMaterial, preset)
|
||||
}
|
||||
|
||||
// Slabs participate in the WebGPU MRT scene pass. Keeping them opaque avoids
|
||||
// pipeline variants that can fail when geometry is regenerated while a
|
||||
|
||||
Reference in New Issue
Block a user