diff --git a/src/App.tsx b/src/App.tsx index 09845bd0e..180fe3363 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,10 @@ import { } from './editor/highlightextension' import { useStore } from './useStore' import { isOverlapping } from './lib/utils' +import { Toolbar } from './Toolbar' +import { BasePlanes } from './components/BasePlanes' +import { SketchPlane } from './components/SketchPlane' +import { Logs } from './components/Logs' const _code = `sketch mySketch { path myPath = lineTo(0,1) @@ -29,15 +33,25 @@ const OrrthographicCamera = OrthographicCamera as any function App() { const cam = useRef() const [code, setCode] = useState(_code) - const { editorView, setEditorView, setSelectionRange, selectionRange } = - useStore( - ({ editorView, setEditorView, setSelectionRange, selectionRange }) => ({ - editorView, - setEditorView, - setSelectionRange, - selectionRange, - }) - ) + const { + editorView, + setEditorView, + setSelectionRange, + selectionRange, + guiMode, + setGuiMode, + removeError, + addLog, + } = useStore((s) => ({ + editorView: s.editorView, + setEditorView: s.setEditorView, + setSelectionRange: s.setSelectionRange, + selectionRange: s.selectionRange, + guiMode: s.guiMode, + setGuiMode: s.setGuiMode, + removeError: s.removeError, + addLog: s.addLog, + })) // const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => { const onChange = (value: string, viewUpdate: ViewUpdate) => { setCode(value) @@ -60,9 +74,21 @@ function App() { >([]) useEffect(() => { try { + if (!code) { + setGeoArray([]) + removeError() + return + } const tokens = lexer(code) const ast = abstractSyntaxTree(tokens) - const programMemory = executor(ast) + const programMemory = executor(ast, { + root: { + log: (a: any) => { + addLog(a) + }, + }, + _sketch: [], + }) const geos: { geo: BufferGeometry; sourceRange: [number, number] }[] = programMemory.root.mySketch .map( @@ -76,14 +102,18 @@ function App() { ) .filter((a: any) => !!a.geo) setGeoArray(geos) + removeError() console.log(programMemory) - } catch (e) { + } catch (e: any) { + setGuiMode({ mode: 'codeError' }) console.log(e) + addLog(e) } }, [code]) return (
+
viewer -
- - - - - - {geoArray.map( - ( - { - geo, - sourceRange, - }: { geo: BufferGeometry; sourceRange: [number, number] }, - index - ) => ( - - ) - )} - + +
+
+ + + + + + {geoArray.map( + ( + { + geo, + sourceRange, + }: { geo: BufferGeometry; sourceRange: [number, number] }, + index + ) => ( + + ) + )} + + + +
+ {guiMode.mode === 'codeError' && ( +
yo
+ )}
diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx new file mode 100644 index 000000000..9bd364341 --- /dev/null +++ b/src/Toolbar.tsx @@ -0,0 +1,27 @@ +import { useStore } from './useStore' + +export const Toolbar = () => { + const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({ + guiMode, + setGuiMode, + })) + return ( +
+ {guiMode.mode === 'default' && ( + + )} + {guiMode.mode !== 'default' && ( + + )} +
+ ) +} diff --git a/src/components/BasePlanes.tsx b/src/components/BasePlanes.tsx new file mode 100644 index 000000000..b1ec89dde --- /dev/null +++ b/src/components/BasePlanes.tsx @@ -0,0 +1,74 @@ +import { useState } from 'react' +import { DoubleSide } from 'three' +import { useStore } from '../useStore' +import { Intersection } from '@react-three/fiber' + +const opacity = 0.1 + +export const BasePlanes = () => { + const [axisIndex, setAxisIndex] = useState(null) + const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({ + guiMode, + setGuiMode, + })) + + const onPointerEvent = ({ + intersections, + }: { + intersections: Intersection[] + }) => { + if (!intersections.length) { + setAxisIndex(null) + return + } + let closestIntersection = intersections[0] + intersections.forEach((intersection) => { + if (intersection.distance < closestIntersection.distance) + closestIntersection = intersection + }) + const smallestIndex = Number(closestIntersection.eventObject.name) + setAxisIndex(smallestIndex) + } + const onClick = () => { + if (guiMode.mode !== 'sketch') { + return null + } + if (guiMode.sketchMode !== 'selectFace') { + return null + } + setGuiMode({ + mode: 'sketch', + sketchMode: 'points', + axis: axisIndex === 0 ? 'yz' : axisIndex === 1 ? 'xy' : 'xz', + }) + } + if (guiMode.mode !== 'sketch') { + return null + } + if (guiMode.sketchMode !== 'selectFace') { + return null + } + return ( + <> + {Array.from({ length: 3 }).map((_, index) => ( + + + + + ))} + + ) +} diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx new file mode 100644 index 000000000..b0968586e --- /dev/null +++ b/src/components/Logs.tsx @@ -0,0 +1,34 @@ +import { useEffect } from 'react' +import { useStore } from '../useStore' + +export const Logs = () => { + const { logs, resetLogs } = useStore(({ logs, resetLogs }) => ({ + logs, + resetLogs, + })) + useEffect(() => { + const element = document.querySelector('.console-tile') + if (element) { + element.scrollTop = element.scrollHeight - element.clientHeight + } + }, [logs]) + return ( +
+
+ +
+ {logs.map((msg, index) => { + return ( +
+                
+                  {'- '}
+                  {String(msg)}
+                
+              
+ ) + })} +
+
+
+ ) +} diff --git a/src/components/SketchPlane.tsx b/src/components/SketchPlane.tsx new file mode 100644 index 000000000..599b9961d --- /dev/null +++ b/src/components/SketchPlane.tsx @@ -0,0 +1,25 @@ +import { useStore } from '../useStore' + +export const SketchPlane = () => { + const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({ + guiMode, + setGuiMode, + })) + if (guiMode.mode !== 'sketch') { + return null + } + if (guiMode.sketchMode !== 'points') { + return null + } + + const ninty = Math.PI / 2 + const rotation: [number, number, number] = [0, 0, 0] + if (guiMode.axis === 'yz') { + rotation[0] = ninty + } else if (guiMode.axis === 'xy') { + rotation[1] = ninty + } else if (guiMode.axis === 'xz') { + rotation[2] = ninty + } + return +} diff --git a/src/useStore.ts b/src/useStore.ts index ea6ba030d..c2bd8397c 100644 --- a/src/useStore.ts +++ b/src/useStore.ts @@ -3,6 +3,23 @@ import { addLineHighlight, EditorView } from './editor/highlightextension' export type Range = [number, number] +type GuiModes = + | { + mode: 'default' + } + | { + mode: 'sketch' + sketchMode: 'points' + axis: 'xy' | 'xz' | 'yz' + } + | { + mode: 'sketch' + sketchMode: 'selectFace' + } + | { + mode: 'codeError' + } + interface StoreState { editorView: EditorView | null setEditorView: (editorView: EditorView) => void @@ -10,6 +27,13 @@ interface StoreState { setHighlightRange: (range: Range) => void selectionRange: [number, number] setSelectionRange: (range: Range) => void + guiMode: GuiModes + lastGuiMode: GuiModes + setGuiMode: (guiMode: GuiModes) => void + removeError: () => void + logs: string[] + addLog: (log: string) => void + resetLogs: () => void } export const useStore = create()((set, get) => ({ @@ -29,4 +53,25 @@ export const useStore = create()((set, get) => ({ setSelectionRange: (selectionRange) => { set({ selectionRange }) }, + guiMode: { mode: 'default' }, + lastGuiMode: { mode: 'default' }, + setGuiMode: (guiMode) => { + const lastGuiMode = get().guiMode + set({ guiMode }) + set({ lastGuiMode }) + }, + removeError: () => { + const lastGuiMode = get().lastGuiMode + const currentGuiMode = get().guiMode + if (currentGuiMode.mode === 'codeError') { + set({ guiMode: lastGuiMode }) + } + }, + logs: [], + addLog: (log) => { + set((state) => ({ logs: [...state.logs, log] })) + }, + resetLogs: () => { + set({ logs: [] }) + }, }))