import { useRef, useState, useMemo } from 'react'; import { Upload, Edit, RefreshCw, RefreshCcw, Sparkles, ImageIcon, Plus, Check } from 'lucide-react'; import { addMaterialToLibrary } from './StyleSelector'; const AddMaterialModal = ({ showModal, onClose, onAddMaterial, newMaterialName, setNewMaterialName, generatedMaterialName, setGeneratedMaterialName, generatedPrompt, setGeneratedPrompt, customPrompt, setCustomPrompt, previewThumbnail, customImagePreview, useCustomImage, isGeneratingPreview, isGeneratingText, showMaterialNameEdit, setShowMaterialNameEdit, showCustomPrompt, setShowCustomPrompt, handleRefreshThumbnail, handleReferenceImageUpload, handleNewMaterialDescription, onStyleSelected, materials }) => { const fileInputRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const [inputValue, setInputValue] = useState(newMaterialName); const [hoveredMaterial, setHoveredMaterial] = useState(null); // Sample materials for the library const sampleMaterials = [ { name: 'Topographic', image: '/samples/topographic.jpeg', prompt: "Transform this sketch into a sculptural form composed of precisely stacked, thin metallic rings or layers. Render it with warm copper/bronze tones with each layer maintaining equal spacing from adjacent layers, creating a topographic map effect. The form should appear to flow and undulate while maintaining the precise parallel structure. Use dramatic studio lighting against a pure black background to highlight the metallic luster and dimensional quality. Render it in a high-end 3D visualization style with perfect definition between each ring layer." }, { name: 'Glow Jelly', image: '/samples/glowjelly.png', prompt: "Transform this sketch into a boobly material. Render it in a high-end 3D visualization style with professional studio lighting against a pure black background. Make it look like an elegant Cinema 4D and Octane rendering with detailed material properties and characteristics. The final result should be an elegant visualization with perfect studio lighting, crisp shadows, and high-end material definition. Specifically, the boobly material should exhibit noticeable internal light scattering and a high degree of dynamic deformation on impact. To achieve the boobly effect, use a combination of Octane's Subsurface Scattering (SSS) and a Dynamic Mesh simulation in Cinema 4D, feeding the displacement output into the Octane material via an Octane Displacement node. The SSS should be tuned for a soft, fleshy translucency with a slight color shift towards red in thinner areas. Implement a high-frequency, low-amplitude noise pattern within the SSS radius to simulate subcutaneous textures. The material's surface should possess a subtle sheen, achieved through a thin-film interference effect in the Octane Glossy material, adding a rainbow iridescence that shifts with the viewing angle. The Dynamic Mesh should simulate realistic jiggle physics; consider using Cinema 4D's Soft Body Dynamics with carefully tuned spring and dampening values. Optimize the Octane scene for render efficiency, focusing on minimizing noise in the SSS and glossy reflections with adequate sample counts and kernel settings. The boobly material possesses a unique combination of squishiness and internal illumination, resulting in a captivating visual texture reminiscent of soft, organic forms. Rendering requires careful balancing of SSS settings and dynamic mesh calculations to achieve a realistic and visually appealing final result." }, { name: 'Gold', image: '/samples/gold.png', prompt: "Transform this sketch into a sculptural form composed of precisely stacked, thin metallic rings or layers. Render it with warm copper/bronze tones with each layer maintaining equal spacing from adjacent layers, creating a topographic map effect. The form should appear to flow and undulate while maintaining the precise parallel structure. Use dramatic studio lighting against a pure black background to highlight the metallic luster and dimensional quality. Render it in a high-end 3D visualization style with perfect definition between each ring layer." }, { name: 'Chinese Porcelain', image: '/samples/porcelain.png', prompt: "Transform this sketch into a ceramic vase featuring traditional blue and white Chinese porcelain designs, including dragons and cloud motifs. Pay close attention to the subtle variations in the blue pigment, creating a hand-painted effect with soft edges and intricate details. The vase should have a slightly glossy surface with gentle reflections. Render in Cinema 4D with Octane, using professional studio lighting to showcase the form and texture against a pure black background. Simulate subtle imperfections and surface irregularities typical of hand-crafted porcelain." }, { name: 'Voxels', image: '/samples/voxels.png', prompt: "Transform this sketch into a physical manifestation of 8-bit voxel art. The rendering should capture the distinct, blocky nature of the medium, with each 'voxel' clearly defined and possessing a matte, slightly rough surface texture. Render the object as if constructed from these individual, quantized blocks, highlighting the stepped edges and discrete color transitions inherent to the 8-bit aesthetic. The professional studio lighting should emphasize the geometric forms and reveal subtle variations in tone across the voxel surfaces. Use Cinema 4D and Octane to create a high-resolution visualization that showcases the material's unique properties against a pure black background, ensuring crisp shadows and a clear definition of each individual voxel. The final result should be an elegant visualization that celebrates the charm and simplicity of 8-bit graphics in a physical form." }, { name: 'Studio Ghibli', image: '/samples/ghibli.png', prompt: "Render the specific subject/scene/character detailed in the provided drawing/text. Faithfully interpret the core elements, composition, and figures present in the input. THEN, apply the following Studio Ghibli stylistic treatment: Aesthetic: Convert the rendering into the characteristic hand-painted look of Studio Ghibli films. Backgrounds: Use lush, painterly backgrounds that complement the subject (if the input lacks a background, create one in the Ghibli style; if it has one, render that background in the Ghibli style). Linework: Employ soft, expressive linework, avoiding harsh digital lines. Color: Utilize a warm, evocative, and harmonious color palette. Atmosphere: Infuse the scene with a Ghibli sense of wonder, nostalgia, or gentle melancholy, appropriate to the subject matter drawn. Details: Add subtle environmental details like wind, detailed foliage, or atmospheric effects typical of Ghibli, where suitable for the depicted scene. Lighting: Implement soft, natural, and atmospheric lighting (dappled sunlight, golden hour, overcast) integrated into the painted style. Goal: The final image must look like a high-quality Ghibli keyframe or background plate that is a clear and recognizable interpretation of the original provided drawing/text, not a generic Ghibli scene." }, { name: 'Purple Fur', image: '/samples/purplefur.png', prompt: "Transform this sketch into a 3D model with a stylized fur material, featuring long, soft, vibrant purple strands with subtle dark grey roots. Pay close attention to the direction and clumping of the fur to mimic the animal form's texture. Render it in Cinema 4D with Octane, using professional studio lighting against a pure black background to accentuate the texture and color depth of the fur, creating soft shadows and highlights." }, { name: 'Water', image: '/samples/water.png', prompt: "Transform this sketch into a dynamic water sculpture. Render it in a high-end 3D visualization style with professional studio lighting against a pure black background. Make it look like an elegant Cinema 4D and Octane rendering with detailed material properties and characteristics, capturing the essence of flowing water. The final result should be an elegant visualization with perfect studio lighting, crisp shadows, and high-end material definition, showcasing the water's transparency, refractive index, and subtle surface ripples. Emphasize the interplay of light and shadow as it passes through the water, highlighting its fluid and dynamic nature." }, { name: 'Shrek', image: '/samples/shrek.png', prompt: "Transform this sketch into a Shrek-like material, capturing the essence of his green, slightly bumpy skin texture. Render it in a high-end 3D visualization style with professional studio lighting against a pure black background. Emphasize the subtle variations in skin tone, the slight translucency that allows for subsurface scattering, and the almost mossy, organic feel. Make it look like an elegant Cinema 4D and Octane rendering with detailed material properties and characteristics, highlighting the way light interacts with the unique surface. The final result should be an elegant visualization with perfect studio lighting, crisp shadows, and high-end material definition, showcasing the Shrek-like skin properties." }, ]; // Create a memoized list of already added material names const addedMaterialNames = useMemo(() => { if (!materials) return []; // Extract all material names (convert to lowercase for case-insensitive comparison) return Object.values(materials) .map(material => material.name?.toLowerCase()) .filter(Boolean); // Filter out undefined/null }, [materials]); // Check if a material is already in the user's library const isMaterialAlreadyAdded = (materialName) => { return addedMaterialNames.includes(materialName.toLowerCase()); }; // Handle clicking outside of the modal to close it const handleClickOutsideModal = (e) => { if (e.target.classList.contains('modalBackdrop')) { onClose(); } }; // Handle selecting a material from the library const handleAddMaterialFromLibrary = (material) => { // Skip if already added if (isMaterialAlreadyAdded(material.name)) { return; } // Create a material object for the library const materialObj = { name: material.name, prompt: material.prompt, image: material.image }; // Add material to library and get the key const materialKey = addMaterialToLibrary(materialObj); // Notify parent to select this material if the callback exists if (onStyleSelected && typeof onStyleSelected === 'function') { onStyleSelected(materialKey); } // Close the modal onClose(); }; // Handle drag and drop events const handleDragEnter = (e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }; const handleDragLeave = (e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); }; const handleDragOver = (e) => { e.preventDefault(); e.stopPropagation(); }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); const files = e.dataTransfer.files; if (files.length > 0) { const file = files[0]; if (file.type.startsWith('image/')) { // Create a synthetic event to pass to handleReferenceImageUpload const syntheticEvent = { target: { files: [file] } }; handleReferenceImageUpload(syntheticEvent); } else { alert('Please drop an image file'); } } }; // Create a debounced version of the material description handler const handleSafeMaterialDescription = (description) => { // Don't process if already generating if (isGeneratingText || isGeneratingPreview) { return; } // Update the name and generate material - this should trigger just one workflow setNewMaterialName(description); handleNewMaterialDescription(description); }; if (!showModal) return null; return (
{ if (e.key === 'Escape') { onClose(); } }} role="dialog" aria-modal="true" >
{/* Material Library Section */}

Material Library

{sampleMaterials.map((material, index) => { const isAlreadyAdded = isMaterialAlreadyAdded(material.name); return ( ); })}
{/* Add Material Form Section */}

Add Material

{/* Input Section */}
{/* Text input */}
{ setInputValue(e.target.value); }} onKeyDown={(e) => { if (e.key === 'Enter' && inputValue.trim()) { e.preventDefault(); handleSafeMaterialDescription(inputValue); } }} className="w-full px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-black pr-10" placeholder="Eg. Bubbles, glass etc" disabled={isGeneratingText || isGeneratingPreview} />
{/* Divider with "or" */}
Or upload a reference image
{/* Image upload */}
!isGeneratingText && fileInputRef.current?.click()} onKeyDown={(e) => { if (!isGeneratingText && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); fileInputRef.current?.click(); } }} onDragEnter={handleDragEnter} onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={handleDrop} style={{ minHeight: "100px" }} role="button" tabIndex={0} > {isGeneratingText && useCustomImage ? (

Analyzing image...

) : ( <>

{isDragging ? 'Drop your image here' : 'Upload your reference image here'}

)}
{/* Review Section */} {(generatedMaterialName || previewThumbnail) && (
{/* Left column: Name and Prompt */}
{/* Material Name - smaller and lighter text */}
setGeneratedMaterialName(e.target.value)} className="w-full px-3 py-2 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all text-gray-900 focus:text-gray-900 text-sm focus:text-base placeholder-gray-400" placeholder="Material Name" />
{/* Prompt - smaller and lighter text */}