add initial components and utility functions for simulation and builder modules

This commit is contained in:
2025-03-25 14:00:03 +05:30
parent 61b3c4ee2c
commit 2303682a15
164 changed files with 13967 additions and 52 deletions

View File

@@ -0,0 +1,186 @@
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import gsap from 'gsap';
import { toast } from 'react-toastify';
import TempLoader from './tempLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as Types from "../../../../types/world/worldTypes";
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants';
async function addAssetModel(
raycaster: THREE.Raycaster,
camera: THREE.Camera,
pointer: THREE.Vector2,
floorGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState,
itemsGroup: Types.RefGroup,
isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh,
socket: Socket<any>,
selectedItem: any,
setSelectedItem: any,
plane: Types.RefMesh,
): Promise<void> {
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
try {
isTempLoader.current = true;
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);
raycaster.setFromCamera(pointer, camera);
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
const planeIntersections = raycaster.intersectObject(plane.current!, true);
const intersectedPlane = planeIntersections[0];
let intersectPoint: THREE.Vector3 | null = null;
if (intersectedFloor && intersectedPlane) {
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
} else if (intersectedFloor) {
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
} else if (intersectedPlane) {
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
}
if (intersectPoint) {
if (intersectPoint.y < 0) {
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
}
const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
return;
} else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
if (cachedModelBlob) {
// console.log(`Added ${selectedItem.name} from indexDB`);
const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
} else {
// console.log(`Added ${selectedItem.name} from Backend`);
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
},
() => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
});
}
}
}
} catch (error) {
console.error('Error fetching asset model:', error);
} finally {
setSelectedItem({});
}
}
async function handleModelLoad(
gltf: any,
intersectPoint: THREE.Vector3,
selectedItem: any,
itemsGroup: Types.RefGroup,
tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState,
socket: Socket<any>
) {
const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.traverse((child: any) => {
if (child) {
child.castShadow = true;
child.receiveShadow = true;
}
});
itemsGroup.current.add(model);
if (tempLoader.current) {
(<any>tempLoader.current.material).dispose();
(<any>tempLoader.current.geometry).dispose();
itemsGroup.current.remove(tempLoader.current);
tempLoader.current = undefined;
}
const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid,
modelname: selectedItem.name,
modelfileID: selectedItem.id,
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
isLocked: false,
isVisible: true
};
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.position,
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
// newFloorItem.modelfileID!,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
};
socket.emit("v1:FloorItems:set", data);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
}
export default addAssetModel;