Add decal management functionality and refactor wall components
This commit is contained in:
48
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
48
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { Decal } from '@react-three/drei'
|
||||||
|
import { useLoader } from '@react-three/fiber';
|
||||||
|
import { useToggleView } from '../../../store/builder/store';
|
||||||
|
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||||
|
|
||||||
|
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||||
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
|
||||||
|
function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) {
|
||||||
|
const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||||
|
const { togglView } = useToggleView();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Decal
|
||||||
|
// debug
|
||||||
|
visible={visible}
|
||||||
|
position={decal.decalPosition}
|
||||||
|
rotation={[0, 0, decal.decalRotation]}
|
||||||
|
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||||
|
userData={decal}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (visible && !togglView && activeModule === 'builder') {
|
||||||
|
if (e.object.userData.decalUuid) {
|
||||||
|
setSelectedDecal(e.object);
|
||||||
|
setSelectedWall(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) {
|
||||||
|
setSelectedDecal(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<meshBasicMaterial
|
||||||
|
map={material}
|
||||||
|
side={THREE.DoubleSide}
|
||||||
|
polygonOffset
|
||||||
|
polygonOffsetFactor={-1}
|
||||||
|
/>
|
||||||
|
</Decal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DecalInstance
|
||||||
@@ -13,12 +13,13 @@ import { useWallClassification } from './helpers/useWallClassification';
|
|||||||
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
|
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
|
||||||
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||||
import * as Constants from '../../../../../types/world/worldConstants';
|
import * as Constants from '../../../../../types/world/worldConstants';
|
||||||
|
import DecalInstance from '../../../Decal/decalInstance';
|
||||||
|
|
||||||
function Wall({ wall }: { readonly wall: Wall }) {
|
function Wall({ wall }: { readonly wall: Wall }) {
|
||||||
const { wallStore } = useSceneContext();
|
const { wallStore } = useSceneContext();
|
||||||
const { walls } = wallStore();
|
const { walls, addDecal } = wallStore();
|
||||||
|
const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||||
const { togglView } = useToggleView();
|
const { togglView } = useToggleView();
|
||||||
const { setSelectedWall } = useBuilderStore();
|
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { camera } = useThree();
|
const { camera } = useThree();
|
||||||
const { wallVisibility } = useWallVisibility();
|
const { wallVisibility } = useWallVisibility();
|
||||||
@@ -112,25 +113,6 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
|||||||
{materials.map((material, index) => (
|
{materials.map((material, index) => (
|
||||||
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
|
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{wall.decals.map((decal) => {
|
|
||||||
return (
|
|
||||||
<Decal
|
|
||||||
// debug
|
|
||||||
position={[decal.decalPosition[0], decal.decalPosition[1], wall.wallThickness / 2]}
|
|
||||||
rotation={[0, 0, decal.decalRotation]}
|
|
||||||
scale={[decal.decalScale, decal.decalScale, 0.001]}
|
|
||||||
userData={decal}
|
|
||||||
>
|
|
||||||
<meshBasicMaterial
|
|
||||||
map={material1WallTexture}
|
|
||||||
side={THREE.DoubleSide}
|
|
||||||
polygonOffset
|
|
||||||
polygonOffsetFactor={-1}
|
|
||||||
/>
|
|
||||||
</Decal>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Base>
|
</Base>
|
||||||
<mesh
|
<mesh
|
||||||
castShadow
|
castShadow
|
||||||
@@ -138,15 +120,39 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
|||||||
position={[centerX, centerY, centerZ]}
|
position={[centerX, centerY, centerZ]}
|
||||||
rotation={[0, -angle, 0]}
|
rotation={[0, -angle, 0]}
|
||||||
userData={wall}
|
userData={wall}
|
||||||
name={`WallRaycastReference_${wall.wallUuid}`}
|
name={`WallReference_${wall.wallUuid}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (visible && !togglView && activeModule === 'builder') {
|
if (visible && !togglView && activeModule === 'builder') {
|
||||||
setSelectedWall(e.object)
|
if (e.object.userData.wallUuid) {
|
||||||
|
setSelectedWall(e.object);
|
||||||
|
setSelectedDecal(null);
|
||||||
|
|
||||||
|
if (wall.decals.length > 0) return;
|
||||||
|
const decal: Decal = {
|
||||||
|
decalUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
decalName: 'Decal',
|
||||||
|
decalId: 'Default Decal',
|
||||||
|
decalPosition: [0, 0, wall.wallThickness / 2 + 0.001],
|
||||||
|
decalRotation: 0,
|
||||||
|
decalScale: 1,
|
||||||
|
decalType: { type: 'Wall', wallUuid: wall.wallUuid }
|
||||||
|
}
|
||||||
|
addDecal(wall.wallUuid, decal);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (selectedWall && selectedWall.userData.wallUuid === wall.wallUuid) {
|
||||||
|
setSelectedWall(null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => { setSelectedWall(null) }}
|
|
||||||
>
|
>
|
||||||
<MeshDiscardMaterial />
|
<MeshDiscardMaterial />
|
||||||
|
|
||||||
|
{wall.decals.map((decal) => (
|
||||||
|
<DecalInstance visible={visible} key={decal.decalUuid} decal={decal} />
|
||||||
|
))}
|
||||||
</mesh>
|
</mesh>
|
||||||
</mesh>
|
</mesh>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function WallInstances() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!toggleView && (
|
{!toggleView && walls.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<mesh name='Walls-Group'>
|
<mesh name='Walls-Group'>
|
||||||
<Geometry useGroups>
|
<Geometry useGroups>
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import useModuleStore from '../../../store/useModuleStore';
|
|||||||
|
|
||||||
function WallGroup() {
|
function WallGroup() {
|
||||||
const { togglView } = useToggleView();
|
const { togglView } = useToggleView();
|
||||||
const { setSelectedWall } = useBuilderStore();
|
const { setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (togglView || activeModule !== 'builder') {
|
if (togglView || activeModule !== 'builder') {
|
||||||
setSelectedWall(null);
|
setSelectedWall(null);
|
||||||
|
setSelectedDecal(null);
|
||||||
}
|
}
|
||||||
}, [togglView, activeModule])
|
}, [togglView, activeModule])
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function PostProcessing() {
|
|||||||
const { selectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem } = useSelectedWallItem();
|
||||||
const { selectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem } = useSelectedFloorItem();
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { selectedAisle, selectedWall } = useBuilderStore();
|
const { selectedAisle, selectedWall, selectedDecal } = useBuilderStore();
|
||||||
|
|
||||||
function flattenChildren(children: any[]) {
|
function flattenChildren(children: any[]) {
|
||||||
const allChildren: any[] = [];
|
const allChildren: any[] = [];
|
||||||
@@ -85,6 +85,21 @@ export default function PostProcessing() {
|
|||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{selectedDecal && (
|
||||||
|
<Outline
|
||||||
|
selection={selectedDecal}
|
||||||
|
selectionLayer={10}
|
||||||
|
width={2000}
|
||||||
|
blendFunction={BlendFunction.ALPHA}
|
||||||
|
edgeStrength={5}
|
||||||
|
resolutionScale={2}
|
||||||
|
pulseSpeed={0}
|
||||||
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
|
blur={true}
|
||||||
|
xRay={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{deletableFloorItem && (
|
{deletableFloorItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(deletableFloorItem.children)}
|
selection={flattenChildren(deletableFloorItem.children)}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ interface BuilderState {
|
|||||||
outsideMaterial: string;
|
outsideMaterial: string;
|
||||||
insideMaterial: string;
|
insideMaterial: string;
|
||||||
|
|
||||||
|
// Decal Settings
|
||||||
|
selectedDecal: Object3D | null;
|
||||||
|
|
||||||
// Aisle General
|
// Aisle General
|
||||||
selectedAisle: Object3D | null;
|
selectedAisle: Object3D | null;
|
||||||
aisleType: AisleTypes;
|
aisleType: AisleTypes;
|
||||||
@@ -41,6 +44,9 @@ interface BuilderState {
|
|||||||
setWallHeight: (height: number) => void;
|
setWallHeight: (height: number) => void;
|
||||||
setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
|
setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
|
||||||
|
|
||||||
|
// Setters - Decal
|
||||||
|
setSelectedDecal: (decal: Object3D | null) => void;
|
||||||
|
|
||||||
// Setters - Aisle General
|
// Setters - Aisle General
|
||||||
setSelectedAisle: (aisle: Object3D | null) => void;
|
setSelectedAisle: (aisle: Object3D | null) => void;
|
||||||
setAisleType: (type: AisleTypes) => void;
|
setAisleType: (type: AisleTypes) => void;
|
||||||
@@ -75,6 +81,8 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
outsideMaterial: 'Default Material',
|
outsideMaterial: 'Default Material',
|
||||||
insideMaterial: 'Material 1',
|
insideMaterial: 'Material 1',
|
||||||
|
|
||||||
|
selectedDecal: null,
|
||||||
|
|
||||||
selectedAisle: null,
|
selectedAisle: null,
|
||||||
aisleType: 'solid-aisle',
|
aisleType: 'solid-aisle',
|
||||||
aisleWidth: 0.1,
|
aisleWidth: 0.1,
|
||||||
@@ -139,6 +147,14 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// === Setters: Decal ===
|
||||||
|
|
||||||
|
setSelectedDecal: (decal: Object3D | null) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedDecal = decal;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// === Setters: Aisle General ===
|
// === Setters: Aisle General ===
|
||||||
|
|
||||||
setSelectedAisle: (aisle: Object3D | null) => {
|
setSelectedAisle: (aisle: Object3D | null) => {
|
||||||
|
|||||||
11
app/src/types/builderTypes.d.ts
vendored
11
app/src/types/builderTypes.d.ts
vendored
@@ -80,11 +80,22 @@ interface Decal {
|
|||||||
decalUuid: string;
|
decalUuid: string;
|
||||||
decalName: string;
|
decalName: string;
|
||||||
decalId: string;
|
decalId: string;
|
||||||
|
decalType: WallDecal | FloorDecal;
|
||||||
decalPosition: [number, number, number];
|
decalPosition: [number, number, number];
|
||||||
decalRotation: number;
|
decalRotation: number;
|
||||||
decalScale: number;
|
decalScale: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WallDecal {
|
||||||
|
type: 'Wall';
|
||||||
|
wallUuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FloorDecal {
|
||||||
|
type: 'Floor';
|
||||||
|
floorUuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Wall {
|
interface Wall {
|
||||||
wallUuid: string;
|
wallUuid: string;
|
||||||
points: [Point, Point];
|
points: [Point, Point];
|
||||||
|
|||||||
Reference in New Issue
Block a user