import * as THREE from 'three'; import { Decal } from '@react-three/drei' import { useToggleView, useToolMode } from '../../../../store/builder/store'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; import { retrieveImage, storeImage } from '../../../../utils/indexDB/idbUtils'; import defaultMaterial from '../../../../assets/image/fallback/fallback decal 1.png'; import useModuleStore from '../../../../store/useModuleStore'; import { useEffect, useRef, useState } from 'react'; import { useDecalEventHandlers } from '../eventHandler/useDecalEventHandlers'; // import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi'; // import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi'; function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalPosition[2] }: { parent: Wall | Floor; visible?: boolean, decal: Decal, zPosition?: number }) { const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const { selectedDecal, deletableDecal, setSelectedDecal, setDeletableDecal } = useBuilderStore(); const { toolMode } = useToolMode(); const { toggleView } = useToggleView(); const { activeModule } = useModuleStore(); const decalRef = useRef(null); useEffect(() => { if (selectedDecal?.decalData.decalUuid === decal.decalUuid && !selectedDecal.decalMesh) { setSelectedDecal({ decalData: selectedDecal.decalData, decalMesh: decalRef.current }); } }, [selectedDecal]) const { handlePointerMissed, handlePointerLeave, handleClick, handlePointerDown, handlePointerEnter } = useDecalEventHandlers({ parent, decal, visible }); const [texture, setTexture] = useState(null); const logDecalStatus = (decalId: string, status: string) => { // console.log(decalId, status); } const loadDefaultTexture = () => { const textureLoader = new THREE.TextureLoader(); textureLoader.load( defaultMaterial, (fallbackTex) => { fallbackTex.name = "default-decal"; setTexture(fallbackTex); logDecalStatus(decal.decalId, 'default-loaded'); }, undefined, (error) => { console.error("Error loading default decal texture:", error); } ); }; const loadDecalTexture = async (decalId: string) => { try { const cachedTexture = THREE.Cache.get(decalId); if (cachedTexture) { setTexture(cachedTexture); logDecalStatus(decalId, 'cache-loaded'); return; } const indexedDBTexture = await retrieveImage(decalId); if (indexedDBTexture) { const blobUrl = URL.createObjectURL(indexedDBTexture); const textureLoader = new THREE.TextureLoader(); textureLoader.load( blobUrl, (tex) => { URL.revokeObjectURL(blobUrl); tex.name = decalId; THREE.Cache.add(decalId, tex); setTexture(tex); logDecalStatus(decalId, 'indexedDB-loaded'); }, undefined, (error) => { console.error(`Error loading texture from IndexedDB:`, error); URL.revokeObjectURL(blobUrl); loadFromBackend(decalId); } ); return; } loadFromBackend(decalId); } catch (error) { console.error("Error loading decal texture:", error); loadDefaultTexture(); } }; const loadFromBackend = (decalId: string) => { const textureUrl = `${url_Backend_dwinzo}/api/v1/DecalImage/${decalId}`; const textureLoader = new THREE.TextureLoader(); textureLoader.load( textureUrl, async (tex) => { tex.name = decalId; THREE.Cache.add(decalId, tex); setTexture(tex); logDecalStatus(decalId, 'backend-loaded'); try { const response = await fetch(textureUrl); const blob = await response.blob(); await storeImage(decalId, blob); } catch (error) { console.error("Error storing texture in IndexedDB:", error); } }, undefined, (error) => { echo.error(`Error loading texture from backend: ${decal.decalName}`); loadDefaultTexture(); } ); }; useEffect(() => { if (decal.decalId) { loadDecalTexture(decal.decalId); } else { loadDefaultTexture(); } }, [decal.decalId]); useEffect(() => { if (!toggleView && activeModule === 'builder') { if (toolMode !== 'cursor') { if (selectedDecal) setSelectedDecal(null); } if (toolMode !== '3D-Delete') { if (deletableDecal) setDeletableDecal(null); } } else { if (selectedDecal) setSelectedDecal(null); if (deletableDecal) setDeletableDecal(null); } }, [toggleView, toolMode, activeModule, selectedDecal, deletableDecal]); return ( { if (e.button === 0) handlePointerDown(e) }} onClick={(e) => { handleClick(e) }} onPointerEnter={(e) => { handlePointerEnter(e) }} onPointerLeave={(e) => { handlePointerLeave(e) }} onPointerMissed={() => handlePointerMissed()} > ) } export default DecalInstance