Includes room interior with floor, walls, glass you can see through, and all uncommitted production changes that were running live. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
297 lines
8.7 KiB
TypeScript
297 lines
8.7 KiB
TypeScript
"use client";
|
|
|
|
import { useRef, useMemo, Suspense } from "react";
|
|
import { useConfiguratorStore, type GlassColor, type Finish } from "@/lib/store";
|
|
import { RoundedBox, useTexture } from "@react-three/drei";
|
|
import * as THREE from "three";
|
|
import {
|
|
Beugelgreep,
|
|
Hoekgreep,
|
|
Maangreep,
|
|
Ovaalgreep,
|
|
Klink,
|
|
UGreep,
|
|
} from "./handles-3d";
|
|
import {
|
|
createStandardGlass,
|
|
createRoundedCornerGlass,
|
|
createInvertedUGlass,
|
|
createNormalUGlass,
|
|
} from "@/lib/glass-patterns";
|
|
import {
|
|
generateDoorAssembly,
|
|
mmToMeters,
|
|
getDividerPositions,
|
|
PROFILE_CORNER_RADIUS,
|
|
type PhysicalPart,
|
|
} from "@/lib/door-models";
|
|
|
|
// ============================================
|
|
// FRAME COLOR MAPPING
|
|
// ============================================
|
|
|
|
const FRAME_COLORS: Record<Finish, string> = {
|
|
zwart: "#1a1a1a",
|
|
brons: "#8B6F47",
|
|
grijs: "#525252",
|
|
goud: "#B8860B",
|
|
beige: "#C8B88A",
|
|
ral: "#4A6741",
|
|
};
|
|
|
|
const FRAME_TEXTURE_PATHS: Record<Finish, string> = {
|
|
zwart: "/textures/proinn/proinn-metaalkleur-zwart.jpg",
|
|
brons: "/textures/proinn/proinn-metaalkleur-brons.jpg",
|
|
grijs: "/textures/proinn/proinn-metaalkleur-antraciet.jpg",
|
|
goud: "/textures/proinn/proinn-metaalkleur-goud.jpg",
|
|
beige: "/textures/proinn/proinn-metaalkleur-beige.jpg",
|
|
ral: "/textures/proinn/proinn-metaalkleur-ral-keuze.jpg",
|
|
};
|
|
|
|
// ============================================
|
|
// GLASS COLOR MAPPING
|
|
// ============================================
|
|
|
|
interface GlassColorProps {
|
|
color: string;
|
|
transmission: number;
|
|
roughness: number;
|
|
}
|
|
|
|
const GLASS_COLOR_MAP: Record<GlassColor, GlassColorProps> = {
|
|
helder: { color: "#eff6ff", transmission: 0.98, roughness: 0.05 },
|
|
grijs: { color: "#3a3a3a", transmission: 0.85, roughness: 0.1 },
|
|
brons: { color: "#8B6F47", transmission: 0.85, roughness: 0.1 },
|
|
"mat-blank": { color: "#e8e8e8", transmission: 0.7, roughness: 0.3 },
|
|
"mat-brons": { color: "#A0845C", transmission: 0.6, roughness: 0.35 },
|
|
"mat-zwart": { color: "#1a1a1a", transmission: 0.5, roughness: 0.4 },
|
|
};
|
|
|
|
// ============================================
|
|
// PHOTOREALISTIC MATERIALS
|
|
// ============================================
|
|
|
|
function SteelMaterialTextured({ color, finish }: { color: string; finish: Finish }) {
|
|
try {
|
|
const texturePath = FRAME_TEXTURE_PATHS[finish];
|
|
const texture = useTexture(texturePath);
|
|
|
|
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
|
|
texture.repeat.set(0.5, 3);
|
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
|
|
return (
|
|
<meshStandardMaterial
|
|
map={texture}
|
|
color={color}
|
|
roughness={0.7}
|
|
metalness={0.6}
|
|
envMapIntensity={1.5}
|
|
/>
|
|
);
|
|
} catch {
|
|
return <SteelMaterialFallback color={color} />;
|
|
}
|
|
}
|
|
|
|
function SteelMaterialFallback({ color }: { color: string }) {
|
|
return (
|
|
<meshStandardMaterial
|
|
color={color}
|
|
roughness={0.7}
|
|
metalness={0.6}
|
|
envMapIntensity={1.5}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function GlassMaterial({ glassColor }: { glassColor: GlassColor }) {
|
|
const props = GLASS_COLOR_MAP[glassColor];
|
|
return (
|
|
<meshPhysicalMaterial
|
|
transmission={props.transmission}
|
|
roughness={props.roughness}
|
|
thickness={0.007}
|
|
ior={1.5}
|
|
color={props.color}
|
|
transparent
|
|
opacity={0.98}
|
|
envMapIntensity={1.0}
|
|
/>
|
|
);
|
|
}
|
|
|
|
// ============================================
|
|
// PHYSICAL PART RENDERER
|
|
// ============================================
|
|
|
|
function PhysicalPartComponent({
|
|
part,
|
|
frameColor,
|
|
finish,
|
|
glassColor,
|
|
}: {
|
|
part: PhysicalPart;
|
|
frameColor: string;
|
|
finish: Finish;
|
|
glassColor: GlassColor;
|
|
}) {
|
|
const x = mmToMeters(part.x);
|
|
const y = mmToMeters(part.y);
|
|
const z = mmToMeters(part.z);
|
|
const width = mmToMeters(part.width);
|
|
const height = mmToMeters(part.height);
|
|
const depth = mmToMeters(part.depth);
|
|
|
|
if (part.isGlass) {
|
|
return (
|
|
<mesh position={[x, y, z]} castShadow receiveShadow>
|
|
<boxGeometry args={[width, height, depth]} />
|
|
<GlassMaterial glassColor={glassColor} />
|
|
</mesh>
|
|
);
|
|
}
|
|
|
|
const cornerRadius = mmToMeters(PROFILE_CORNER_RADIUS);
|
|
|
|
return (
|
|
<RoundedBox
|
|
args={[width, height, depth]}
|
|
radius={cornerRadius}
|
|
smoothness={4}
|
|
position={[x, y, z]}
|
|
castShadow
|
|
receiveShadow
|
|
>
|
|
<Suspense fallback={<SteelMaterialFallback color={frameColor} />}>
|
|
<SteelMaterialTextured color={frameColor} finish={finish} />
|
|
</Suspense>
|
|
</RoundedBox>
|
|
);
|
|
}
|
|
|
|
// ============================================
|
|
// MAIN DOOR COMPONENT
|
|
// ============================================
|
|
|
|
export function Door3DEnhanced() {
|
|
const { doorType, gridType, finish, handle, glassPattern, glassColor, doorLeafWidth, height } =
|
|
useConfiguratorStore();
|
|
const doorRef = useRef<THREE.Group>(null);
|
|
|
|
const frameColor = FRAME_COLORS[finish] || "#1a1a1a";
|
|
|
|
const doorAssembly = useMemo(
|
|
() => generateDoorAssembly(doorType, gridType, doorLeafWidth, height),
|
|
[doorType, gridType, doorLeafWidth, height]
|
|
);
|
|
|
|
const doorWidth = mmToMeters(doorLeafWidth);
|
|
const doorHeight = mmToMeters(height);
|
|
const stileWidth = mmToMeters(40);
|
|
const railDepth = mmToMeters(40);
|
|
const dividerPositions = getDividerPositions(gridType, height);
|
|
|
|
return (
|
|
<group ref={doorRef} position={[0, doorHeight / 2, 0]}>
|
|
{/* RENDER ALL PHYSICAL PARTS */}
|
|
{doorAssembly.parts.map((part, index) => (
|
|
<PhysicalPartComponent
|
|
key={`${part.type}-${index}`}
|
|
part={part}
|
|
frameColor={frameColor}
|
|
finish={finish}
|
|
glassColor={glassColor}
|
|
/>
|
|
))}
|
|
|
|
{/* GLASS PANELS WITH PATTERNS */}
|
|
{glassPattern !== "standard" && (
|
|
<group position={[0, 0, 0.005]}>
|
|
{glassPattern === "dt9-rounded" && (
|
|
<mesh castShadow receiveShadow>
|
|
<extrudeGeometry
|
|
args={[
|
|
createRoundedCornerGlass(
|
|
doorWidth - stileWidth * 2,
|
|
doorHeight - stileWidth * 2,
|
|
0.12
|
|
),
|
|
{ depth: 0.01, bevelEnabled: false },
|
|
]}
|
|
/>
|
|
<GlassMaterial glassColor={glassColor} />
|
|
</mesh>
|
|
)}
|
|
|
|
{glassPattern === "dt10-ushape" && dividerPositions.length > 0 && (
|
|
<>
|
|
<mesh
|
|
position={[0, (doorHeight / 4 + dividerPositions[0]) / 2, 0]}
|
|
castShadow
|
|
receiveShadow
|
|
>
|
|
<extrudeGeometry
|
|
args={[
|
|
createInvertedUGlass(
|
|
doorWidth - stileWidth * 2,
|
|
Math.abs(doorHeight / 2 - stileWidth - dividerPositions[0])
|
|
),
|
|
{ depth: 0.01, bevelEnabled: false },
|
|
]}
|
|
/>
|
|
<GlassMaterial glassColor={glassColor} />
|
|
</mesh>
|
|
|
|
<mesh
|
|
position={[
|
|
0,
|
|
(-doorHeight / 4 + dividerPositions[dividerPositions.length - 1]) / 2,
|
|
0,
|
|
]}
|
|
castShadow
|
|
receiveShadow
|
|
>
|
|
<extrudeGeometry
|
|
args={[
|
|
createNormalUGlass(
|
|
doorWidth - stileWidth * 2,
|
|
Math.abs(
|
|
-doorHeight / 2 +
|
|
stileWidth -
|
|
dividerPositions[dividerPositions.length - 1]
|
|
)
|
|
),
|
|
{ depth: 0.01, bevelEnabled: false },
|
|
]}
|
|
/>
|
|
<GlassMaterial glassColor={glassColor} />
|
|
</mesh>
|
|
</>
|
|
)}
|
|
</group>
|
|
)}
|
|
|
|
{/* PROFESSIONAL 3D HANDLES */}
|
|
{handle === "beugelgreep" && (
|
|
<Beugelgreep finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
{handle === "hoekgreep" && (
|
|
<Hoekgreep finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
{handle === "maangreep" && (
|
|
<Maangreep finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
{handle === "ovaalgreep" && (
|
|
<Ovaalgreep finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
{handle === "klink" && (
|
|
<Klink finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
{handle === "u-greep" && (
|
|
<UGreep finish={finish} doorWidth={doorWidth} doorHeight={doorHeight} railDepth={railDepth} stileWidth={stileWidth} />
|
|
)}
|
|
</group>
|
|
);
|
|
}
|