import { type CeilingNode, useRegistry } from '@pascal-app/core' import { useMemo, useRef } from 'react' import { float, mix, positionWorld, smoothstep } from 'three/tsl' import { BackSide, FrontSide, type Mesh, MeshBasicNodeMaterial } from 'three/webgpu' import { useNodeEvents } from '../../../hooks/use-node-events' import { DEFAULT_CEILING_MATERIAL } from '../../../lib/materials' import { NodeRenderer } from '../node-renderer' const gridScale = 5 const gridX = positionWorld.x.mul(gridScale).fract() const gridY = positionWorld.z.mul(gridScale).fract() const lineWidth = 0.05 const lineX = smoothstep(lineWidth, 0, gridX).add(smoothstep(1.0 - lineWidth, 1.0, gridX)) const lineY = smoothstep(lineWidth, 0, gridY).add(smoothstep(1.0 - lineWidth, 1.0, gridY)) const gridPattern = lineX.max(lineY) const gridOpacity = mix(float(0.2), float(0.6), gridPattern) function createCeilingMaterials(color: string = '#999999') { const topMaterial = new MeshBasicNodeMaterial({ color, transparent: true, depthWrite: false, side: FrontSide, }) topMaterial.opacityNode = gridOpacity const bottomMaterial = new MeshBasicNodeMaterial({ color, transparent: true, side: BackSide, }) return { topMaterial, bottomMaterial } } export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { const ref = useRef(null!) useRegistry(node.id, 'ceiling', ref) const handlers = useNodeEvents(node, 'ceiling') const materials = useMemo(() => { const mat = node.material if (mat) { const props = mat.properties const color = props?.color || '#999999' return createCeilingMaterials(color) } return { topMaterial: createCeilingMaterials().topMaterial, bottomMaterial: DEFAULT_CEILING_MATERIAL, } }, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]) return ( {node.children.map((childId) => ( ))} ) }