feat: Implement wall asset management features including creation, instances, and rendering; enhance wall properties input validation
This commit is contained in:
@@ -133,11 +133,17 @@ const SelectedWallProperties = () => {
|
|||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Height"
|
label="Height"
|
||||||
value={height}
|
value={height}
|
||||||
|
min={1}
|
||||||
|
max={25}
|
||||||
|
step={1}
|
||||||
onChange={handleHeightChange}
|
onChange={handleHeightChange}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Thickness"
|
label="Thickness"
|
||||||
value={thickness}
|
value={thickness}
|
||||||
|
min={0.1}
|
||||||
|
max={2}
|
||||||
|
step={0.1}
|
||||||
onChange={handleThicknessChange}
|
onChange={handleThicknessChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,11 +63,17 @@ const WallProperties = () => {
|
|||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Height"
|
label="Height"
|
||||||
value={`${wallHeight}`}
|
value={`${wallHeight}`}
|
||||||
|
min={1}
|
||||||
|
max={25}
|
||||||
|
step={1}
|
||||||
onChange={(val) => handleHeightChange(val)}
|
onChange={(val) => handleHeightChange(val)}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Thickness"
|
label="Thickness"
|
||||||
value={`${wallThickness}`}
|
value={`${wallThickness}`}
|
||||||
|
min={0.1}
|
||||||
|
max={2}
|
||||||
|
step={0.1}
|
||||||
onChange={(val) => handleThicknessChange(val)}
|
onChange={(val) => handleThicknessChange(val)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
|||||||
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
|
||||||
function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) {
|
function DecalInstance({ visible = true, decal, zPosition = decal.decalPosition[2] }: { visible?: boolean, decal: Decal, zPosition?: number }) {
|
||||||
const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore();
|
const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||||
const { togglView } = useToggleView();
|
const { togglView } = useToggleView();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
@@ -17,7 +17,7 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De
|
|||||||
<Decal
|
<Decal
|
||||||
// debug
|
// debug
|
||||||
visible={visible}
|
visible={visible}
|
||||||
position={decal.decalPosition}
|
position={[decal.decalPosition[0], decal.decalPosition[1], zPosition]}
|
||||||
rotation={[0, 0, decal.decalRotation]}
|
rotation={[0, 0, decal.decalRotation]}
|
||||||
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||||
userData={decal}
|
userData={decal}
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
const onDrop = (event: any) => {
|
const onDrop = (event: DragEvent) => {
|
||||||
if (!event.dataTransfer?.files[0]) return;
|
if (!event.dataTransfer?.files[0]) return;
|
||||||
|
|
||||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { Bvh } from "@react-three/drei";
|
import { Geometry } from "@react-three/csg";
|
||||||
|
|
||||||
////////// Zustand State Imports //////////
|
////////// Zustand State Imports //////////
|
||||||
|
|
||||||
@@ -39,16 +39,14 @@ import ZoneGroup from "./zone/zoneGroup";
|
|||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
||||||
import { getUserData } from "../../functions/getUserData";
|
import { getUserData } from "../../functions/getUserData";
|
||||||
|
import WallAssetGroup from "./wallAsset/wallAssetGroup";
|
||||||
|
|
||||||
export default function Builder() {
|
export default function Builder() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>();
|
||||||
|
const plane = useRef<THREE.Mesh>(null);
|
||||||
|
const csgRef = useRef<any>(null);
|
||||||
|
|
||||||
// Assigning the scene and camera from the Three.js state to the references.
|
const { toggleView } = useToggleView();
|
||||||
|
|
||||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
|
||||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
|
||||||
|
|
||||||
const { toggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
|
||||||
const { setToolMode } = useToolMode();
|
const { setToolMode } = useToolMode();
|
||||||
const { setRoofVisibility } = useRoofVisibility();
|
const { setRoofVisibility } = useRoofVisibility();
|
||||||
const { setWallVisibility } = useWallVisibility();
|
const { setWallVisibility } = useWallVisibility();
|
||||||
@@ -59,14 +57,6 @@ export default function Builder() {
|
|||||||
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
|
||||||
// const dracoLoader = new DRACOLoader();
|
|
||||||
|
|
||||||
// dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
|
||||||
// loader.setDRACOLoader(dracoLoader);
|
|
||||||
|
|
||||||
////////// All Toggle's //////////
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
setHoveredLine(null);
|
setHoveredLine(null);
|
||||||
@@ -91,29 +81,31 @@ export default function Builder() {
|
|||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
////////// Return //////////
|
useFrame(() => {
|
||||||
|
if (csgRef.current) {
|
||||||
|
csgRef.current.update();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Ground grid={grid} plane={plane} />
|
<Ground plane={plane} />
|
||||||
|
|
||||||
<SocketResponses />
|
<SocketResponses />
|
||||||
|
|
||||||
{/* <WallsAndWallItems
|
|
||||||
CSGGroup={CSGGroup}
|
|
||||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
|
||||||
selectedItemsIndex={selectedItemsIndex}
|
|
||||||
currentWallItem={currentWallItem}
|
|
||||||
csg={csg}
|
|
||||||
lines={lines}
|
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<AssetsGroup plane={plane} />
|
<AssetsGroup plane={plane} />
|
||||||
|
|
||||||
<AislesGroup />
|
<mesh name='Walls-And-WallAssets-Group'>
|
||||||
|
<Geometry ref={csgRef} useGroups>
|
||||||
|
|
||||||
<WallGroup />
|
<WallGroup />
|
||||||
|
|
||||||
|
<WallAssetGroup />
|
||||||
|
|
||||||
|
</Geometry>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
<AislesGroup />
|
||||||
|
|
||||||
<FloorGroup />
|
<FloorGroup />
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
|||||||
<MeshDiscardMaterial />
|
<MeshDiscardMaterial />
|
||||||
|
|
||||||
{wall.decals.map((decal) => (
|
{wall.decals.map((decal) => (
|
||||||
<DecalInstance visible={visible} key={decal.decalUuid} decal={decal} />
|
<DecalInstance zPosition={wall.wallThickness / 2 + 0.001} visible={visible} key={decal.decalUuid} decal={decal} />
|
||||||
))}
|
))}
|
||||||
</mesh>
|
</mesh>
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
|
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
|
||||||
import { Geometry } from '@react-three/csg';
|
|
||||||
import { Html, Extrude } from '@react-three/drei';
|
import { Html, Extrude } from '@react-three/drei';
|
||||||
import { useLoader } from '@react-three/fiber';
|
import { useLoader } from '@react-three/fiber';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
@@ -44,13 +43,9 @@ function WallInstances() {
|
|||||||
<>
|
<>
|
||||||
{!toggleView && walls.length > 1 && (
|
{!toggleView && walls.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<mesh name='Walls-Group'>
|
{walls.map((wall) => (
|
||||||
<Geometry useGroups>
|
<WallInstance key={wall.wallUuid} wall={wall} />
|
||||||
{walls.map((wall) => (
|
))}
|
||||||
<WallInstance key={wall.wallUuid} wall={wall} />
|
|
||||||
))}
|
|
||||||
</Geometry>
|
|
||||||
</mesh>
|
|
||||||
|
|
||||||
<group name='Wall-Floors-Group'>
|
<group name='Wall-Floors-Group'>
|
||||||
{rooms.map((room, index) => (
|
{rooms.map((room, index) => (
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
||||||
|
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||||
|
import { Base, Geometry, Subtraction } from '@react-three/csg';
|
||||||
|
import { useFrame } from '@react-three/fiber';
|
||||||
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
|
|
||||||
|
function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||||
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
const { wallStore } = useSceneContext();
|
||||||
|
const { walls, getWallById } = wallStore();
|
||||||
|
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
|
||||||
|
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||||
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
|
const csgRef = useRef<any>(null);
|
||||||
|
const wall = useMemo(() => getWallById(wallAsset.wallUuid), [getWallById, wallAsset.wallUuid, walls]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loader = new GLTFLoader();
|
||||||
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
|
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||||
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
const loadModel = async () => {
|
||||||
|
try {
|
||||||
|
// Check Cache
|
||||||
|
const assetId = wallAsset.assetId;
|
||||||
|
const cachedModel = THREE.Cache.get(assetId);
|
||||||
|
if (cachedModel) {
|
||||||
|
setGltfScene(cachedModel.scene.clone());
|
||||||
|
calculateBoundingBox(cachedModel.scene);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check IndexedDB
|
||||||
|
const indexedDBModel = await retrieveGLTF(assetId);
|
||||||
|
if (indexedDBModel) {
|
||||||
|
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||||
|
loader.load(blobUrl, (gltf) => {
|
||||||
|
URL.revokeObjectURL(blobUrl);
|
||||||
|
THREE.Cache.remove(blobUrl);
|
||||||
|
THREE.Cache.add(assetId, gltf);
|
||||||
|
setGltfScene(gltf.scene.clone());
|
||||||
|
calculateBoundingBox(gltf.scene);
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
(error) => {
|
||||||
|
echo.error(`[IndexedDB] Error loading ${wallAsset.modelName}:`);
|
||||||
|
URL.revokeObjectURL(blobUrl);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch from Backend
|
||||||
|
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`;
|
||||||
|
const handleBackendLoad = async (gltf: GLTF) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(modelUrl);
|
||||||
|
const modelBlob = await response.blob();
|
||||||
|
await storeGLTF(assetId, modelBlob);
|
||||||
|
THREE.Cache.add(assetId, gltf);
|
||||||
|
setGltfScene(gltf.scene.clone());
|
||||||
|
calculateBoundingBox(gltf.scene);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[Backend] Error storing/loading ${wallAsset.modelName}:`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loader.load(
|
||||||
|
modelUrl,
|
||||||
|
handleBackendLoad,
|
||||||
|
undefined,
|
||||||
|
(error) => {
|
||||||
|
echo.error(`[Backend] Error loading ${wallAsset.modelName}:`);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to load model:", wallAsset.assetId, err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculateBoundingBox = (scene: THREE.Object3D) => {
|
||||||
|
const box = new THREE.Box3().setFromObject(scene);
|
||||||
|
setBoundingBox(box);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadModel();
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (csgRef.current) {
|
||||||
|
csgRef.current.update();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!gltfScene || !boundingBox || !wall) { return null }
|
||||||
|
const size = new THREE.Vector3();
|
||||||
|
boundingBox.getSize(size);
|
||||||
|
const center = new THREE.Vector3();
|
||||||
|
boundingBox.getCenter(center);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<group
|
||||||
|
key={wallAsset.modelUuid}
|
||||||
|
name={wallAsset.modelName}
|
||||||
|
ref={groupRef}
|
||||||
|
position={wallAsset.position}
|
||||||
|
rotation={wallAsset.rotation}
|
||||||
|
visible={wallAsset.isVisible}
|
||||||
|
userData={wallAsset}
|
||||||
|
>
|
||||||
|
<Subtraction position={[center.x, center.y, center.z]} scale={[size.x, size.y, wall.wallThickness + 0.05]}>
|
||||||
|
<Geometry ref={csgRef}>
|
||||||
|
<Base geometry={new THREE.BoxGeometry()} />
|
||||||
|
</Geometry>
|
||||||
|
</Subtraction>
|
||||||
|
{gltfScene && (
|
||||||
|
<mesh
|
||||||
|
onClick={() => {
|
||||||
|
console.log(wallAsset);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<primitive object={gltfScene} />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WallAssetInstance
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useSceneContext } from '../../../scene/sceneContext'
|
||||||
|
import { useToggleView } from '../../../../store/builder/store';
|
||||||
|
import WallAssetInstance from './Instances/wallAssetInstance';
|
||||||
|
|
||||||
|
function WallAssetInstances() {
|
||||||
|
const { wallAssetStore } = useSceneContext();
|
||||||
|
const { wallAssets } = wallAssetStore();
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log('wallAssets: ', wallAssets);
|
||||||
|
}, [wallAssets])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
{!toggleView && wallAssets.length > 0 && (
|
||||||
|
<>
|
||||||
|
{wallAssets.map((wallAsset) => (
|
||||||
|
<WallAssetInstance key={wallAsset.modelUuid} wallAsset={wallAsset} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WallAssetInstances
|
||||||
85
app/src/modules/builder/wallAsset/wallAssetCreator.tsx
Normal file
85
app/src/modules/builder/wallAsset/wallAssetCreator.tsx
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { useThree } from '@react-three/fiber';
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useSelectedItem, useSocketStore, useToggleView } from '../../../store/builder/store';
|
||||||
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
import { MathUtils, Vector3 } from 'three';
|
||||||
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
|
|
||||||
|
function WallAssetCreator() {
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { pointer, camera, raycaster, scene, gl } = useThree();
|
||||||
|
const { togglView } = useToggleView();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { wallAssetStore } = useSceneContext();
|
||||||
|
const { addWallAsset } = wallAssetStore();
|
||||||
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
|
|
||||||
|
function closestPointOnLineSegment(p: Vector3, a: Vector3, b: Vector3) {
|
||||||
|
const ab = new Vector3().subVectors(b, a);
|
||||||
|
const ap = new Vector3().subVectors(p, a);
|
||||||
|
|
||||||
|
const abLengthSq = ab.lengthSq();
|
||||||
|
const dot = ap.dot(ab);
|
||||||
|
const t = Math.max(0, Math.min(1, dot / abLengthSq));
|
||||||
|
|
||||||
|
return new Vector3().copy(a).add(ab.multiplyScalar(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
const onDrop = (event: DragEvent) => {
|
||||||
|
if (!event.dataTransfer?.files[0]) return;
|
||||||
|
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category === 'Fenestration') {
|
||||||
|
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||||
|
const intersect = intersects.find((intersect) => intersect.object.name.includes('WallReference'));
|
||||||
|
|
||||||
|
if (intersect) {
|
||||||
|
const wall = intersect.object.userData as Wall;
|
||||||
|
const closestPoint = closestPointOnLineSegment(
|
||||||
|
new Vector3(intersect.point.x, 0, intersect.point.z),
|
||||||
|
new Vector3(...wall.points[0].position),
|
||||||
|
new Vector3(...wall.points[1].position)
|
||||||
|
)
|
||||||
|
|
||||||
|
const wallRotation = intersect.object.rotation.clone();
|
||||||
|
|
||||||
|
const newWallAsset: WallAsset = {
|
||||||
|
modelName: selectedItem.name,
|
||||||
|
modelUuid: MathUtils.generateUUID(),
|
||||||
|
wallUuid: wall.wallUuid,
|
||||||
|
wallAssetType: selectedItem.subCategory,
|
||||||
|
assetId: selectedItem.id,
|
||||||
|
position: [closestPoint.x, selectedItem.subCategory === "fixed-move" ? 0 : intersect.point.y, closestPoint.z],
|
||||||
|
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
opacity: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
addWallAsset(newWallAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!togglView && activeModule === 'builder') {
|
||||||
|
canvasElement.addEventListener('drop', onDrop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener('drop', onDrop);
|
||||||
|
};
|
||||||
|
|
||||||
|
}, [gl, camera, togglView, activeModule, socket, selectedItem, setSelectedItem]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WallAssetCreator
|
||||||
17
app/src/modules/builder/wallAsset/wallAssetGroup.tsx
Normal file
17
app/src/modules/builder/wallAsset/wallAssetGroup.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import WallAssetCreator from './wallAssetCreator'
|
||||||
|
import WallAssetInstances from './Instances/wallAssetInstances'
|
||||||
|
|
||||||
|
function WallAssetGroup() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<WallAssetCreator />
|
||||||
|
|
||||||
|
<WallAssetInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WallAssetGroup
|
||||||
@@ -29,7 +29,6 @@ function ZoneGroup() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (projectId && selectedVersion) {
|
if (projectId && selectedVersion) {
|
||||||
getZonesApi(projectId, selectedVersion?.versionId || '').then((zones) => {
|
getZonesApi(projectId, selectedVersion?.versionId || '').then((zones) => {
|
||||||
console.log('zones: ', zones);
|
|
||||||
if (zones && zones.length > 0) {
|
if (zones && zones.length > 0) {
|
||||||
setZones(zones);
|
setZones(zones);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { useTileDistance, useToggleView } from "../../../store/builder/store";
|
import { useTileDistance, useToggleView } from "../../../store/builder/store";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
|
|
||||||
const Ground = ({ grid, plane }: any) => {
|
const Ground = ({ plane }: any) => {
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { planeValue, gridValue } = useTileDistance();
|
const { planeValue, gridValue } = useTileDistance();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<mesh name="Ground">
|
<mesh name="Ground">
|
||||||
<mesh
|
<mesh
|
||||||
ref={grid}
|
|
||||||
name="Grid"
|
name="Grid"
|
||||||
position={!toggleView ? CONSTANTS.gridConfig.position3D : CONSTANTS.gridConfig.position2D}
|
position={!toggleView ? CONSTANTS.gridConfig.position3D : CONSTANTS.gridConfig.position2D}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const upsertZoneApi = async (
|
|||||||
zoneData: Zone
|
zoneData: Zone
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertZone`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/upsertZone`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer <access_token>",
|
Authorization: "Bearer <access_token>",
|
||||||
|
|||||||
2
app/src/types/builderTypes.d.ts
vendored
2
app/src/types/builderTypes.d.ts
vendored
@@ -51,9 +51,11 @@ type Assets = Asset[];
|
|||||||
interface WallAsset {
|
interface WallAsset {
|
||||||
modelUuid: string;
|
modelUuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
wallAssetType: string;
|
||||||
assetId: string;
|
assetId: string;
|
||||||
wallUuid: string;
|
wallUuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user