massive overhall to how program memory works and how artifacts their metada are rendered

This commit is contained in:
Kurt Hutten IrevDev
2023-01-08 16:37:31 +11:00
parent 0515acf459
commit 9ad6b946c0
13 changed files with 1090 additions and 884 deletions

View File

@ -3,110 +3,22 @@ import {
getNodePathFromSourceRange,
getNodeFromPath,
CallExpression,
VariableDeclarator,
} from '../lang/abstractSyntaxTree'
import { changeArguments } from '../lang/modifyAst'
import { ViewerArtifact } from '../lang/executor'
import {
ExtrudeGroup,
ExtrudeSurface,
SketchGroup,
Path,
Rotation,
Position,
} from '../lang/executor'
import { BufferGeometry } from 'three'
import { useStore } from '../useStore'
import { isOverlapping } from '../lib/utils'
import { LineGeos } from '../lang/engine'
import { Vector3, DoubleSide, Quaternion, Vector2 } from 'three'
import { combineTransformsAlt } from '../lang/sketch'
import { Vector3, DoubleSide, Quaternion } from 'three'
import { useSetCursor } from '../hooks/useSetCursor'
function SketchLine({
geo,
sourceRange,
forceHighlight = false,
}: {
geo: LineGeos
sourceRange: [number, number]
forceHighlight?: boolean
}) {
const { setHighlightRange } = useStore(({ setHighlightRange }) => ({
setHighlightRange,
}))
const onClick = useSetCursor(sourceRange)
// This reference will give us direct access to the mesh
const ref = useRef<BufferGeometry | undefined>() as any
const [hovered, setHover] = useState(false)
return (
<>
<mesh
ref={ref}
onPointerOver={(event) => {
setHover(true)
setHighlightRange(sourceRange)
}}
onPointerOut={(event) => {
setHover(false)
setHighlightRange([0, 0])
}}
onClick={onClick}
>
<primitive object={geo.line} />
<meshStandardMaterial
color={hovered ? 'hotpink' : forceHighlight ? 'skyblue' : 'orange'}
/>
</mesh>
<MovingSphere
geo={geo.tip}
sourceRange={sourceRange}
editorCursor={forceHighlight}
/>
</>
)
}
function ExtrudeWall({
geo,
sourceRange,
forceHighlight = false,
}: {
geo: BufferGeometry
sourceRange: [number, number]
forceHighlight?: boolean
}) {
const { setHighlightRange } = useStore(
({ setHighlightRange, selectionRange, guiMode, setGuiMode, ast }) => ({
setHighlightRange,
selectionRange,
guiMode,
setGuiMode,
ast,
})
)
const onClick = useSetCursor(sourceRange)
// This reference will give us direct access to the mesh
const ref = useRef<BufferGeometry | undefined>() as any
const [hovered, setHover] = useState(false)
return (
<>
<mesh
ref={ref}
onPointerOver={(event) => {
setHover(true)
setHighlightRange(sourceRange)
}}
onPointerOut={(event) => {
setHover(false)
setHighlightRange([0, 0])
}}
onClick={onClick}
>
<primitive object={geo} />
<meshStandardMaterial
side={DoubleSide}
color={hovered ? 'hotpink' : forceHighlight ? 'skyblue' : 'orange'}
/>
</mesh>
</>
)
}
const roundOff = (num: number, places: number): number => {
const x = Math.pow(10, places)
return Math.round(num * x) / x
@ -116,15 +28,19 @@ function MovingSphere({
geo,
sourceRange,
editorCursor,
rotation,
position,
}: {
geo: BufferGeometry
sourceRange: [number, number]
editorCursor: boolean
rotation: Rotation
position: Position
}) {
const ref = useRef<BufferGeometry | undefined>() as any
const detectionPlaneRef = useRef<BufferGeometry | undefined>() as any
const lastPointerRef = useRef<Vector3>(new Vector3())
const point2DRef = useRef<Vector2>(new Vector2())
const point2DRef = useRef<Vector3>(new Vector3())
const [hovered, setHover] = useState(false)
const [isMouseDown, setIsMouseDown] = useState(false)
@ -154,14 +70,22 @@ function MovingSphere({
const handleMouseUp = () => {
if (isMouseDown && ast) {
const thePath = getNodePathFromSourceRange(ast, sourceRange)
let [x, y] = [
roundOff(point2DRef.current.x, 2),
roundOff(point2DRef.current.y, 2),
]
const yo = point2DRef.current.clone()
const inverseQuaternion = new Quaternion()
if (
guiMode.mode === 'canEditSketch' ||
(guiMode.mode === 'sketch' && guiMode.sketchMode === 'sketchEdit')
) {
inverseQuaternion.set(...guiMode.rotation)
inverseQuaternion.invert()
}
yo.sub(new Vector3(...position).applyQuaternion(inverseQuaternion))
let [x, y] = [roundOff(yo.x, 2), roundOff(yo.y, 2)]
let theNewPoints: [number, number] = [x, y]
const { modifiedAst } = changeArguments(ast, thePath, theNewPoints)
updateAst(modifiedAst)
ref.current.position.set(0, 0, 0)
console.log('reset position')
ref.current.position.set(...position)
}
setIsMouseDown(false)
}
@ -169,31 +93,32 @@ function MovingSphere({
return () => {
window.removeEventListener('mouseup', handleMouseUp)
}
}, [isMouseDown, ast])
}, [isMouseDown])
let clickDetectPlaneQuaternion = new Quaternion()
let position = new Vector3(0, 0, 0)
if (
const inEditMode =
guiMode.mode === 'canEditSketch' ||
(guiMode.mode === 'sketch' && guiMode.sketchMode === 'sketchEdit')
) {
clickDetectPlaneQuaternion = guiMode.quaternion.clone()
position = new Vector3(...guiMode.position)
let clickDetectPlaneQuaternion = new Quaternion()
if (inEditMode) {
clickDetectPlaneQuaternion = new Quaternion(...rotation)
}
return (
<>
<mesh
position={position}
quaternion={rotation}
ref={ref}
onPointerOver={(event) => {
setHover(true)
inEditMode && setHover(true)
setHighlightRange(sourceRange)
}}
onPointerOut={(event) => {
setHover(false)
setHighlightRange([0, 0])
}}
onPointerDown={() => setIsMouseDown(true)}
onPointerDown={() => inEditMode && setIsMouseDown(true)}
>
<primitive object={geo} scale={hovered ? 2 : 1} />
<meshStandardMaterial
@ -202,7 +127,6 @@ function MovingSphere({
</mesh>
{isMouseDown && (
<mesh
position={position}
quaternion={clickDetectPlaneQuaternion}
onPointerMove={(a) => {
const point = a.point
@ -213,13 +137,11 @@ function MovingSphere({
guiMode.mode === 'canEditSketch' ||
(guiMode.mode === 'sketch' && guiMode.sketchMode === 'sketchEdit')
) {
inverseQuaternion.copy(guiMode.quaternion.clone().invert())
inverseQuaternion.set(...guiMode.rotation)
inverseQuaternion.invert()
}
transformedPoint.applyQuaternion(inverseQuaternion)
transformedPoint.sub(
position.clone().applyQuaternion(inverseQuaternion)
)
point2DRef.current.set(transformedPoint.x, transformedPoint.y)
point2DRef.current.copy(transformedPoint)
if (
lastPointerRef.current.x === 0 &&
@ -248,7 +170,7 @@ function MovingSphere({
ref.current.position.add(
diff.applyQuaternion(inverseQuaternion.invert())
)
lastPointerRef.current.set(point.x, point.y, point.z)
lastPointerRef.current.copy(point.clone())
}
}}
>
@ -266,86 +188,258 @@ function MovingSphere({
}
export function RenderViewerArtifacts({
artifact,
forceHighlight = false,
artifacts,
}: {
artifact: ViewerArtifact
forceHighlight?: boolean
artifacts: (ExtrudeGroup | SketchGroup)[]
}) {
const { selectionRange, guiMode, ast, setGuiMode, programMemory } = useStore(
({ selectionRange, guiMode, ast, setGuiMode, programMemory }) => ({
selectionRange,
guiMode,
ast,
setGuiMode,
programMemory,
})
)
const [editorCursor, setEditorCursor] = useState(false)
useEffect(() => {
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
setEditorCursor(shouldHighlight && artifact.type !== 'sketch')
}, [selectionRange, artifact.sourceRange])
useEffect(() => {
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
if (
shouldHighlight &&
(guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') &&
artifact.type === 'sketch' &&
ast
) {
const pathToNode = getNodePathFromSourceRange(ast, artifact.sourceRange)
const varDec: VariableDeclarator = getNodeFromPath(
ast,
pathToNode,
'VariableDeclarator'
)
const varName = varDec?.id?.name
const { quaternion, position } = combineTransformsAlt(
programMemory.root[varName]
)
setGuiMode({ mode: 'canEditSketch', pathToNode, quaternion, position })
} else if (
!shouldHighlight &&
guiMode.mode === 'canEditSketch' &&
artifact.type === 'sketch'
) {
setGuiMode({ mode: 'default' })
}
}, [selectionRange, artifact.sourceRange, ast, guiMode.mode, setGuiMode])
if (artifact.type === 'sketchLine') {
const { geo, sourceRange } = artifact
return (
<SketchLine
geo={geo}
sourceRange={sourceRange}
forceHighlight={forceHighlight || editorCursor}
/>
)
}
if (artifact.type === 'sketchBase') {
console.log('BASE TODO')
return null
}
if (artifact.type === 'extrudeWall') {
return (
<ExtrudeWall
geo={artifact.geo}
sourceRange={artifact.sourceRange}
forceHighlight={forceHighlight || editorCursor}
/>
)
}
return (
<>
{artifact.children.map((artifact, index) => (
<RenderViewerArtifacts
artifact={artifact}
key={index}
forceHighlight={forceHighlight || editorCursor}
/>
{artifacts.map((artifact, i) => (
<RenderViewerArtifact key={i} artifact={artifact} />
))}
</>
)
}
function RenderViewerArtifact({
artifact,
}: {
artifact: ExtrudeGroup | SketchGroup
}) {
const { selectionRange, guiMode, ast, setGuiMode } = useStore(
({ selectionRange, guiMode, ast, setGuiMode }) => ({
selectionRange,
guiMode,
ast,
setGuiMode,
})
)
const [editorCursor, setEditorCursor] = useState(false)
useEffect(() => {
const shouldHighlight = isOverlapping(
artifact.__meta.slice(-1)[0].sourceRange,
selectionRange
)
setEditorCursor(shouldHighlight)
}, [selectionRange, artifact.__meta])
useEffect(() => {
const shouldHighlight = artifact.__meta.some((aMeta) =>
isOverlapping(aMeta.sourceRange, selectionRange)
)
if (
shouldHighlight &&
(guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') &&
ast &&
artifact.type === 'sketchGroup'
) {
const pathToNode = getNodePathFromSourceRange(
ast,
artifact.__meta[0].sourceRange
)
const { rotation, position } = artifact
setGuiMode({ mode: 'canEditSketch', pathToNode, rotation, position })
} else if (
!shouldHighlight &&
guiMode.mode === 'canEditSketch' &&
artifact.type === 'sketchGroup'
) {
setGuiMode({ mode: 'default' })
}
}, [selectionRange, artifact, ast, guiMode.mode, setGuiMode])
if (artifact.type === 'sketchGroup') {
return (
<>
{artifact.value.map((geoInfo, key) => (
<PathRender
geoInfo={geoInfo}
key={key}
forceHighlight={editorCursor}
rotation={artifact.rotation}
position={artifact.position}
/>
))}
</>
)
}
if (artifact.type === 'extrudeGroup') {
return (
<>
{artifact.value.map((geoInfo, key) => (
<WallRender
geoInfo={geoInfo}
key={key}
forceHighlight={editorCursor}
rotation={artifact.rotation}
position={artifact.position}
/>
))}
</>
)
}
return null
}
function WallRender({
geoInfo,
forceHighlight = false,
rotation,
position,
}: {
geoInfo: ExtrudeSurface
forceHighlight?: boolean
rotation: Rotation
position: Position
}) {
const { setHighlightRange, selectionRange } = useStore(
({ setHighlightRange, selectionRange }) => ({
setHighlightRange,
selectionRange,
})
)
const onClick = useSetCursor(geoInfo.__geoMeta.sourceRange)
// This reference will give us direct access to the mesh
const ref = useRef<BufferGeometry | undefined>() as any
const [hovered, setHover] = useState(false)
const [editorCursor, setEditorCursor] = useState(false)
useEffect(() => {
const shouldHighlight = isOverlapping(
geoInfo.__geoMeta.sourceRange,
selectionRange
)
setEditorCursor(shouldHighlight)
}, [selectionRange, geoInfo])
return (
<>
<mesh
quaternion={rotation}
position={position}
ref={ref}
onPointerOver={(event) => {
setHover(true)
setHighlightRange(geoInfo.__geoMeta.sourceRange)
}}
onPointerOut={(event) => {
setHover(false)
setHighlightRange([0, 0])
}}
onClick={onClick}
>
<primitive object={geoInfo.__geoMeta.geo} />
<meshStandardMaterial
side={DoubleSide}
color={
hovered
? 'hotpink'
: forceHighlight || editorCursor
? 'skyblue'
: 'orange'
}
/>
</mesh>
</>
)
}
function PathRender({
geoInfo,
forceHighlight = false,
rotation,
position,
}: {
geoInfo: Path
forceHighlight?: boolean
rotation: Rotation
position: Position
}) {
const { selectionRange } = useStore(({ selectionRange }) => ({
selectionRange,
}))
const [editorCursor, setEditorCursor] = useState(false)
useEffect(() => {
const shouldHighlight = isOverlapping(
geoInfo.__geoMeta.sourceRange,
selectionRange
)
setEditorCursor(shouldHighlight)
}, [selectionRange, geoInfo])
return (
<>
{geoInfo.__geoMeta.geos.map((meta, i) => {
if (meta.type === 'line') {
return (
<LineRender
key={i}
geo={meta.geo}
sourceRange={geoInfo.__geoMeta.sourceRange}
forceHighlight={forceHighlight || editorCursor}
rotation={rotation}
position={position}
/>
)
}
if (meta.type === 'lineEnd') {
return (
<MovingSphere
key={i}
geo={meta.geo}
sourceRange={geoInfo.__geoMeta.sourceRange}
editorCursor={forceHighlight || editorCursor}
rotation={rotation}
position={position}
/>
)
}
})}
</>
)
}
function LineRender({
geo,
sourceRange,
forceHighlight = false,
rotation,
position,
}: {
geo: BufferGeometry
sourceRange: [number, number]
forceHighlight?: boolean
rotation: Rotation
position: Position
}) {
const { setHighlightRange } = useStore(({ setHighlightRange }) => ({
setHighlightRange,
}))
const onClick = useSetCursor(sourceRange)
// This reference will give us direct access to the mesh
const ref = useRef<BufferGeometry | undefined>() as any
const [hovered, setHover] = useState(false)
return (
<>
<mesh
quaternion={rotation}
position={position}
ref={ref}
onPointerOver={(event) => {
setHover(true)
setHighlightRange(sourceRange)
}}
onPointerOut={(event) => {
setHover(false)
setHighlightRange([0, 0])
}}
onClick={onClick}
>
<primitive object={geo} />
<meshStandardMaterial
color={hovered ? 'hotpink' : forceHighlight ? 'skyblue' : 'orange'}
/>
</mesh>
</>
)
}