2021-03-26 17:25:28 +08:00
|
|
|
|
|
|
|
|
2021-04-02 16:04:42 +08:00
|
|
|
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
2021-04-01 16:20:50 +08:00
|
|
|
import './app.css'
|
2021-03-26 17:25:28 +08:00
|
|
|
|
2021-03-28 20:00:31 +08:00
|
|
|
import { Provider, useDispatch, useSelector } from 'react-redux'
|
2021-04-07 03:46:16 +08:00
|
|
|
|
2021-04-02 16:04:42 +08:00
|
|
|
import { FaCube, FaEdit } from 'react-icons/fa'
|
2021-04-06 12:52:19 +08:00
|
|
|
import { MdEdit, MdDone, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
2021-04-03 03:33:09 +08:00
|
|
|
import * as Icon from "./icons";
|
2021-04-07 03:46:16 +08:00
|
|
|
// import { color } from './shared'
|
2021-03-28 20:00:31 +08:00
|
|
|
|
2021-03-27 03:18:11 +08:00
|
|
|
export const Root = ({ store }) => (
|
2021-03-26 17:25:28 +08:00
|
|
|
<Provider store={store}>
|
2021-03-27 03:18:11 +08:00
|
|
|
<App></App>
|
2021-03-26 17:25:28 +08:00
|
|
|
</Provider>
|
|
|
|
);
|
2021-03-27 03:18:11 +08:00
|
|
|
|
2021-03-30 13:13:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2021-03-27 03:18:11 +08:00
|
|
|
const App = () => {
|
2021-03-28 20:00:31 +08:00
|
|
|
const dispatch = useDispatch()
|
2021-03-29 18:27:34 +08:00
|
|
|
const treeEntries = useSelector(state => state.treeEntries)
|
2021-04-06 12:52:19 +08:00
|
|
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
2021-03-30 13:13:13 +08:00
|
|
|
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-03-30 13:13:13 +08:00
|
|
|
useEffect(() => {
|
2021-04-06 12:52:19 +08:00
|
|
|
if (!activeSketchId) {
|
2021-03-31 07:20:24 +08:00
|
|
|
sc.canvas.addEventListener('pointermove', sc.onHover)
|
|
|
|
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
2021-04-01 16:20:50 +08:00
|
|
|
return () => {
|
|
|
|
sc.canvas.removeEventListener('pointermove', sc.onHover)
|
|
|
|
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
2021-03-31 07:20:24 +08:00
|
|
|
}
|
2021-03-30 13:13:13 +08:00
|
|
|
}
|
2021-04-06 12:52:19 +08:00
|
|
|
}, [activeSketchId])
|
2021-03-27 03:18:11 +08:00
|
|
|
|
2021-03-28 20:00:31 +08:00
|
|
|
|
2021-04-02 08:19:14 +08:00
|
|
|
const btnz = [
|
2021-04-06 12:52:19 +08:00
|
|
|
activeSketchId ?
|
2021-04-05 11:52:17 +08:00
|
|
|
[MdDone, () => {
|
2021-04-06 12:52:19 +08:00
|
|
|
treeEntries.byId[activeSketchId].deactivate()
|
2021-04-05 11:52:17 +08:00
|
|
|
sc.activeSketch = null
|
|
|
|
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
|
|
|
}, 'Finish'] :
|
2021-04-02 16:04:42 +08:00
|
|
|
[FaEdit, sc.addSketch, 'Sketch']
|
2021-04-02 08:19:14 +08:00
|
|
|
,
|
2021-04-06 12:52:19 +08:00
|
|
|
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
|
|
|
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
2021-04-06 13:40:47 +08:00
|
|
|
[Icon.Subtract, () => {
|
2021-04-06 12:52:19 +08:00
|
|
|
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
|
|
|
// console.log('here')
|
|
|
|
const [m1, m2] = sc.selected
|
2021-04-06 13:40:47 +08:00
|
|
|
const mesh = subtract(m1, m2)
|
|
|
|
|
|
|
|
console.log(mesh, 'meshres')
|
|
|
|
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
2021-04-06 12:52:19 +08:00
|
|
|
sc.render()
|
|
|
|
forceUpdate()
|
|
|
|
}, 'Subtract'],
|
|
|
|
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
|
|
|
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension'],
|
|
|
|
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line'],
|
|
|
|
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc'],
|
2021-04-02 08:19:14 +08:00
|
|
|
]
|
2021-04-01 18:10:00 +08:00
|
|
|
|
2021-04-06 12:52:19 +08:00
|
|
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
|
|
|
|
2021-04-07 02:31:14 +08:00
|
|
|
return <>
|
|
|
|
<div className='absolute flex ml-auto mr-auto left-0 right-0 justify-center'>
|
|
|
|
{/* <div className='absolute flex justify-center'> */}
|
2021-04-06 13:40:47 +08:00
|
|
|
{
|
|
|
|
btnz.map(([Icon, fcn, txt], idx) => (
|
|
|
|
<div className="btn flex items-center justify-start p-1 text-lg" key={idx}
|
|
|
|
onClick={fcn}
|
|
|
|
>
|
|
|
|
<Icon className="w-6 h-6" />
|
|
|
|
<div className="ml-2">{txt}</div>
|
|
|
|
</div>
|
|
|
|
))
|
|
|
|
}
|
|
|
|
</div>
|
2021-04-02 08:19:14 +08:00
|
|
|
|
2021-04-07 02:31:14 +08:00
|
|
|
<div className='absolute left-0 top-36 w-40 flex flex-col'>
|
2021-04-06 12:52:19 +08:00
|
|
|
{treeEntries.allIds.map((entId, idx) => (
|
2021-04-02 16:04:42 +08:00
|
|
|
<TreeEntry key={idx} entId={entId} />
|
2021-03-28 20:00:31 +08:00
|
|
|
))}
|
|
|
|
</div>
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-04-07 02:31:14 +08:00
|
|
|
</>
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-03-28 20:00:31 +08:00
|
|
|
}
|
|
|
|
|
2021-04-02 16:04:42 +08:00
|
|
|
const TreeEntry = ({ entId }) => {
|
|
|
|
|
2021-04-06 12:52:19 +08:00
|
|
|
const treeEntries = useSelector(state => state.treeEntries.byId)
|
|
|
|
const dispatch = useDispatch()
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-04-06 12:52:19 +08:00
|
|
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-04-03 03:33:09 +08:00
|
|
|
let obj3d, entry;
|
2021-04-05 11:52:17 +08:00
|
|
|
|
2021-04-03 03:33:09 +08:00
|
|
|
entry = treeEntries[entId]
|
|
|
|
|
|
|
|
if (entId[0] == "s") {
|
|
|
|
obj3d = treeEntries[entId].obj3d
|
2021-04-02 16:04:42 +08:00
|
|
|
} else {
|
2021-04-03 03:33:09 +08:00
|
|
|
obj3d = treeEntries[entId]
|
2021-04-02 16:04:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
|
|
|
|
2021-04-03 03:33:09 +08:00
|
|
|
const vis = obj3d.visible
|
2021-04-02 16:04:42 +08:00
|
|
|
|
2021-04-05 16:05:53 +08:00
|
|
|
return <div className='bg-gray-50 flex justify-between w-full'>
|
2021-04-02 16:04:42 +08:00
|
|
|
<div className="btn"
|
|
|
|
onPointerEnter={() => {
|
|
|
|
if (entId[0] == 'm') {
|
2021-04-07 03:46:16 +08:00
|
|
|
// entry.material.color.set(color.hover)
|
2021-04-02 16:04:42 +08:00
|
|
|
sc.render()
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
onPointerLeave={() => {
|
|
|
|
const obj = entry
|
|
|
|
if (entId[0] == 'm' && !sc.selected.includes(obj)) {
|
2021-04-07 03:46:16 +08:00
|
|
|
// obj.material.color.set(color.mesh)
|
2021-04-02 16:04:42 +08:00
|
|
|
sc.render()
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
onPointerDown={() => {
|
|
|
|
if (entId[0] == 'm') {
|
|
|
|
sc.selected.push(
|
|
|
|
entry
|
|
|
|
)
|
|
|
|
sc.render()
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{entId}
|
|
|
|
</div>
|
2021-04-06 13:40:47 +08:00
|
|
|
<div className='flex'>
|
|
|
|
<div className='btn'
|
|
|
|
onClick={() => {
|
|
|
|
activeSketchId && treeEntries[activeSketchId].deactivate()
|
|
|
|
entry.activate()
|
2021-04-07 02:31:14 +08:00
|
|
|
sc.clearSelection()
|
2021-04-06 13:40:47 +08:00
|
|
|
sc.activeSketch = entry;
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<MdEdit />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='btn'
|
|
|
|
onClick={() => {
|
|
|
|
dispatch({ type: 'delete-node', id: entId })
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<MdDelete />
|
|
|
|
</div>
|
|
|
|
{
|
|
|
|
vis ?
|
|
|
|
<div className='btn'
|
|
|
|
onClick={() => {
|
|
|
|
obj3d.visible = false;
|
|
|
|
sc.render()
|
|
|
|
forceUpdate()
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<MdVisibility />
|
|
|
|
</div>
|
|
|
|
:
|
|
|
|
<div className='btn'
|
|
|
|
onClick={() => {
|
|
|
|
obj3d.visible = true;
|
|
|
|
sc.render()
|
|
|
|
forceUpdate()
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<MdVisibilityOff />
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
|
2021-04-02 16:04:42 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-04-06 13:40:47 +08:00
|
|
|
const subtract = (m1, m2) => {
|
2021-04-03 03:33:09 +08:00
|
|
|
// //Create a bsp tree from each of the meshes
|
2021-04-05 11:52:17 +08:00
|
|
|
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
2021-04-06 12:52:19 +08:00
|
|
|
|
2021-04-03 03:33:09 +08:00
|
|
|
|
2021-04-05 11:52:17 +08:00
|
|
|
let bspA = BoolOp.fromMesh(m1)
|
|
|
|
let bspB = BoolOp.fromMesh(m2)
|
2021-04-03 03:33:09 +08:00
|
|
|
m1.visible = false
|
|
|
|
m2.visible = false
|
|
|
|
|
|
|
|
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
|
|
|
|
|
|
|
let bspResult = bspA.subtract(bspB)
|
|
|
|
|
|
|
|
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
|
|
|
|
2021-04-05 11:52:17 +08:00
|
|
|
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
2021-04-06 12:52:19 +08:00
|
|
|
meshResult.userData.type = 'mesh'
|
2021-04-06 13:40:47 +08:00
|
|
|
meshResult.name = `${m1.name}-${m2.name}`
|
2021-04-03 03:33:09 +08:00
|
|
|
|
|
|
|
sc.obj3d.add(meshResult)
|
2021-04-06 12:52:19 +08:00
|
|
|
|
|
|
|
return meshResult
|
2021-04-03 03:33:09 +08:00
|
|
|
|
|
|
|
}
|
2021-04-02 16:04:42 +08:00
|
|
|
|