diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 8216310..824062f 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import Search from "../../ui/inputs/Search"; import { getCategoryAsset } from "../../../services/factoryBuilder/asset/assets/getCategoryAsset"; import { fetchAssets } from "../../../services/marketplace/fetchAssets"; -import { useDecalStore, useSelectedItem } from "../../../store/builder/store"; +import { useDecalStore, useDroppedDecal, useSelectedItem } from "../../../store/builder/store"; // images ------------------- import vehicle from "../../../assets/image/categories/vehicles.png"; @@ -21,7 +21,6 @@ import { HangTagIcon, NavigationIcon, } from "../../icons/ExportCommonIcons"; -import { assert } from "console"; import { getCategoryDecals } from "../../../services/factoryBuilder/asset/decals/getCategoryDecals"; // ------------------------------------- @@ -46,6 +45,7 @@ interface CategoryListProp { } const Assets: React.FC = () => { const { setSelectedItem } = useSelectedItem(); + const { setDroppedDecal } = useDroppedDecal(); const [searchValue, setSearchValue] = useState(""); const [selectedCategory, setSelectedCategory] = useState(null); const [categoryAssets, setCategoryAssets] = useState([]); @@ -304,15 +304,11 @@ const Assets: React.FC = () => { alt={asset.decalName} className="asset-image" onPointerDown={() => { - setSelectedItem({ - name: asset.decalName, - id: asset.id, - type: - asset.type === "undefined" - ? undefined - : asset.type, + setDroppedDecal({ category: asset.category, - // subType: asset.subType, + decalName: asset.decalName, + decalImage: asset.decalImage, + decalId: asset.id }); }} /> diff --git a/app/src/modules/builder/Decal/decal.tsx b/app/src/modules/builder/Decal/decal.tsx new file mode 100644 index 0000000..d14e150 --- /dev/null +++ b/app/src/modules/builder/Decal/decal.tsx @@ -0,0 +1,14 @@ +import DecalCreator from './decalCreator/decalCreator' + +function Decal() { + + return ( + <> + + + + + ) +} + +export default Decal \ No newline at end of file diff --git a/app/src/modules/builder/Decal/decalCreator/decalCreator.tsx b/app/src/modules/builder/Decal/decalCreator/decalCreator.tsx new file mode 100644 index 0000000..4335afc --- /dev/null +++ b/app/src/modules/builder/Decal/decalCreator/decalCreator.tsx @@ -0,0 +1,44 @@ +import { useEffect } from 'react'; +import { useThree } from '@react-three/fiber'; +import { useDroppedDecal } from '../../../../store/builder/store'; +import useModuleStore from '../../../../store/useModuleStore'; + +function DecalCreator() { + const { droppedDecal } = useDroppedDecal(); + const { activeModule } = useModuleStore(); + const { controls, gl, pointer, camera, raycaster, scene } = useThree(); + + useEffect(() => { + const canvasElement = gl.domElement; + + const onDrop = (event: DragEvent) => { + console.log('event: ', event); + console.log('droppedDecal: ', droppedDecal); + if (!event.dataTransfer?.files[0]) return; + + if (droppedDecal) { + } + }; + + const onDragOver = (event: any) => { + event.preventDefault(); + }; + + if (activeModule === "builder") { + canvasElement.addEventListener("drop", onDrop); + canvasElement.addEventListener("dragover", onDragOver); + } + + return () => { + canvasElement.removeEventListener("drop", onDrop); + canvasElement.removeEventListener("dragover", onDragOver); + }; + }, [droppedDecal, camera, activeModule, controls]); + + return ( + <> + + ) +} + +export default DecalCreator \ No newline at end of file diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance/decalInstance.tsx similarity index 93% rename from app/src/modules/builder/Decal/decalInstance.tsx rename to app/src/modules/builder/Decal/decalInstance/decalInstance.tsx index d414419..bbb1268 100644 --- a/app/src/modules/builder/Decal/decalInstance.tsx +++ b/app/src/modules/builder/Decal/decalInstance/decalInstance.tsx @@ -1,19 +1,19 @@ import * as THREE from 'three'; import { CameraControls, Decal } from '@react-three/drei' import { useLoader, useThree } from '@react-three/fiber'; -import { useSocketStore, useToggleView, useToolMode } from '../../../store/builder/store'; -import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; +import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; -import defaultMaterial from '../../../assets/textures/floor/wall-tex.png'; -import useModuleStore from '../../../store/useModuleStore'; -import { useSceneContext } from '../../scene/sceneContext'; +import defaultMaterial from '../../../../assets/textures/floor/wall-tex.png'; +import useModuleStore from '../../../../store/useModuleStore'; +import { useSceneContext } from '../../../scene/sceneContext'; import { useEffect, useRef } from 'react'; -import { getUserData } from '../../../functions/getUserData'; -import { useVersionContext } from '../version/versionContext'; +import { getUserData } from '../../../../functions/getUserData'; +import { useVersionContext } from '../../version/versionContext'; import { useParams } from 'react-router-dom'; -// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; -// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +// 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 { setSelectedWall, setSelectedFloor, selectedDecal, deletableDecal, setSelectedDecal, setDeletableDecal } = useBuilderStore(); diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 9d36efc..0205a4c 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -363,6 +363,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) { setLeft(relativeX); } }; + const onMouseUp = (evt: any) => { setIsRenameMode(false); } diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index ef310fc..d7b8d34 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -33,13 +33,14 @@ import AssetsGroup from "./asset/assetsGroup"; import DxfFile from "./dfx/LoadBlueprint"; import AislesGroup from "./aisle/aislesGroup"; import WallGroup from "./wall/wallGroup"; +import WallAssetGroup from "./wallAsset/wallAssetGroup"; import FloorGroup from "./floor/floorGroup"; import ZoneGroup from "./zone/zoneGroup"; +import Decal from "./Decal/decal"; import { useParams } from "react-router-dom"; import { useBuilderStore } from "../../store/builder/useBuilderStore"; import { getUserData } from "../../functions/getUserData"; -import WallAssetGroup from "./wallAsset/wallAssetGroup"; export default function Builder() { const state = useThree(); @@ -106,6 +107,8 @@ export default function Builder() { + + diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 50d3536..f52fa4d 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -10,7 +10,7 @@ import { useToggleView, useWallVisibility } from '../../../../../store/builder/s import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; import * as Constants from '../../../../../types/world/worldConstants'; -import DecalInstance from '../../../Decal/decalInstance'; +import DecalInstance from '../../../Decal/decalInstance/decalInstance'; import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 2f72b98..c022bb7 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -163,6 +163,21 @@ export const useSelectedItem = create((set: any) => ({ setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); +type DroppedDecalType = { + category: string; + decalName: string; + decalImage: string; + decalId: string; +}; + +export const useDroppedDecal = create<{ + droppedDecal: DroppedDecalType | null; + setDroppedDecal: (x: DroppedDecalType | null) => void; +}>((set) => ({ + droppedDecal: null, + setDroppedDecal: (x) => set({ droppedDecal: x }), +})); + export const useNavMesh = create((set: any) => ({ navMesh: null, setNavMesh: (x: any) => set({ navMesh: x }), diff --git a/app/src/utils/indexDB/idbUtils.ts b/app/src/utils/indexDB/idbUtils.ts index 24b1448..79910bb 100644 --- a/app/src/utils/indexDB/idbUtils.ts +++ b/app/src/utils/indexDB/idbUtils.ts @@ -1,15 +1,19 @@ -const DB_NAME = 'GLTFStorage'; -const STORE_NAME = 'models'; const DB_VERSION = 1; -export function initializeDB(): Promise { +const ASSET_DB_NAME = 'GLTFStorage'; +const ASSET_STORE_NAME = 'models'; + +const IMAGE_DB_NAME = 'ImageStorage'; +const IMAGE_STORE_NAME = 'images'; + +export function initializeAssetDB(): Promise { return new Promise((resolve, reject) => { - const request = indexedDB.open(DB_NAME, DB_VERSION); + const request = indexedDB.open(ASSET_DB_NAME, DB_VERSION); request.onupgradeneeded = () => { const db = request.result; - if (!db.objectStoreNames.contains(STORE_NAME)) { - db.createObjectStore(STORE_NAME); + if (!db.objectStoreNames.contains(ASSET_STORE_NAME)) { + db.createObjectStore(ASSET_STORE_NAME); } }; @@ -19,11 +23,11 @@ export function initializeDB(): Promise { } export async function storeGLTF(key: string, file: Blob): Promise { - const db = await initializeDB(); + const db = await initializeAssetDB(); return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readwrite'); - const store = transaction.objectStore(STORE_NAME); + const transaction = db.transaction(ASSET_STORE_NAME, 'readwrite'); + const store = transaction.objectStore(ASSET_STORE_NAME); const request = store.put(file, key); request.onsuccess = () => resolve(); @@ -32,11 +36,53 @@ export async function storeGLTF(key: string, file: Blob): Promise { } export async function retrieveGLTF(key: string): Promise { - const db = await initializeDB(); + const db = await initializeAssetDB(); return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readonly'); - const store = transaction.objectStore(STORE_NAME); + const transaction = db.transaction(ASSET_STORE_NAME, 'readonly'); + const store = transaction.objectStore(ASSET_STORE_NAME); + const request = store.get(key); + + request.onsuccess = () => resolve(request.result as Blob | undefined); + request.onerror = () => reject(request.error); + }); +} + +export function initializeImageDB(): Promise { + return new Promise((resolve, reject) => { + const request = indexedDB.open(IMAGE_DB_NAME, DB_VERSION); + + request.onupgradeneeded = () => { + const db = request.result; + if (!db.objectStoreNames.contains(IMAGE_STORE_NAME)) { + db.createObjectStore(IMAGE_STORE_NAME); + } + }; + + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); +} + +export async function storeImage(key: string, file: Blob): Promise { + const db = await initializeImageDB(); + + return new Promise((resolve, reject) => { + const transaction = db.transaction(IMAGE_STORE_NAME, 'readwrite'); + const store = transaction.objectStore(IMAGE_STORE_NAME); + const request = store.put(file, key); + + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); +} + +export async function retrieveImage(key: string): Promise { + const db = await initializeImageDB(); + + return new Promise((resolve, reject) => { + const transaction = db.transaction(IMAGE_STORE_NAME, 'readonly'); + const store = transaction.objectStore(IMAGE_STORE_NAME); const request = store.get(key); request.onsuccess = () => resolve(request.result as Blob | undefined);