Compare commits
1 Commits
pierremtb/
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
c03357d897 |
@ -34,7 +34,7 @@ const FRAMES_TO_ANIMATE_IN = 30
|
|||||||
|
|
||||||
const tempQuaternion = new Quaternion() // just used for maths
|
const tempQuaternion = new Quaternion() // just used for maths
|
||||||
|
|
||||||
type interactionType = 'pan' | 'rotate' | 'zoom'
|
export type CameraInteractionType = 'pan' | 'rotate' | 'zoom'
|
||||||
|
|
||||||
interface ThreeCamValues {
|
interface ThreeCamValues {
|
||||||
position: Vector3
|
position: Vector3
|
||||||
@ -1219,8 +1219,8 @@ function _getInteractionType(
|
|||||||
enablePan: boolean,
|
enablePan: boolean,
|
||||||
enableRotate: boolean,
|
enableRotate: boolean,
|
||||||
enableZoom: boolean
|
enableZoom: boolean
|
||||||
): interactionType | 'none' {
|
): CameraInteractionType | 'none' {
|
||||||
let state: interactionType | 'none' = 'none'
|
let state: CameraInteractionType | 'none' = 'none'
|
||||||
if (enablePan && interactionGuards.pan.callback(event)) return 'pan'
|
if (enablePan && interactionGuards.pan.callback(event)) return 'pan'
|
||||||
if (enableRotate && interactionGuards.rotate.callback(event)) return 'rotate'
|
if (enableRotate && interactionGuards.rotate.callback(event)) return 'rotate'
|
||||||
if (enableZoom && interactionGuards.zoom.dragCallback(event)) return 'zoom'
|
if (enableZoom && interactionGuards.zoom.dragCallback(event)) return 'zoom'
|
||||||
|
@ -105,7 +105,7 @@ export const ModelingMachineProvider = ({
|
|||||||
settings: {
|
settings: {
|
||||||
context: {
|
context: {
|
||||||
app: { theme, enableSSAO },
|
app: { theme, enableSSAO },
|
||||||
modeling: { defaultUnit, highlightEdges, showScaleGrid },
|
modeling: { defaultUnit, highlightEdges, showScaleGrid, mouseControls },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = useSettingsAuthContext()
|
} = useSettingsAuthContext()
|
||||||
@ -509,6 +509,7 @@ export const ModelingMachineProvider = ({
|
|||||||
settings: {
|
settings: {
|
||||||
theme: theme.current,
|
theme: theme.current,
|
||||||
highlightEdges: highlightEdges.current,
|
highlightEdges: highlightEdges.current,
|
||||||
|
mouseControls: mouseControls.current,
|
||||||
},
|
},
|
||||||
}).catch(reportRejection)
|
}).catch(reportRejection)
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ import { isDesktop } from 'lib/isDesktop'
|
|||||||
import { PATHS } from 'lib/paths'
|
import { PATHS } from 'lib/paths'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { TextToCad_type } from '@kittycad/lib/dist/types/src/models'
|
import { TextToCad_type } from '@kittycad/lib/dist/types/src/models'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
Box3,
|
Box3,
|
||||||
Color,
|
Color,
|
||||||
@ -15,6 +15,7 @@ import {
|
|||||||
LineSegments,
|
LineSegments,
|
||||||
Mesh,
|
Mesh,
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
|
MOUSE,
|
||||||
OrthographicCamera,
|
OrthographicCamera,
|
||||||
Scene,
|
Scene,
|
||||||
Vector3,
|
Vector3,
|
||||||
@ -29,6 +30,15 @@ import { commandBarMachine } from 'machines/commandBarMachine'
|
|||||||
import { EventFrom } from 'xstate'
|
import { EventFrom } from 'xstate'
|
||||||
import { fileMachine } from 'machines/fileMachine'
|
import { fileMachine } from 'machines/fileMachine'
|
||||||
import { reportRejection } from 'lib/trap'
|
import { reportRejection } from 'lib/trap'
|
||||||
|
import {
|
||||||
|
CameraControls,
|
||||||
|
CameraInteractionType,
|
||||||
|
} from 'clientSideScene/CameraControls'
|
||||||
|
import {
|
||||||
|
cameraMouseDragGuards,
|
||||||
|
CameraSystem,
|
||||||
|
MouseGuard,
|
||||||
|
} from 'lib/cameraControls'
|
||||||
|
|
||||||
const CANVAS_SIZE = 128
|
const CANVAS_SIZE = 128
|
||||||
const PROMPT_TRUNCATE_LENGTH = 128
|
const PROMPT_TRUNCATE_LENGTH = 128
|
||||||
@ -118,8 +128,14 @@ export function ToastTextToCadSuccess({
|
|||||||
settings: {
|
settings: {
|
||||||
theme: Themes
|
theme: Themes
|
||||||
highlightEdges: boolean
|
highlightEdges: boolean
|
||||||
|
mouseControls: CameraSystem
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
|
const interactionGuards = useMemo(
|
||||||
|
() => cameraMouseDragGuards[settings.mouseControls],
|
||||||
|
[settings.mouseControls]
|
||||||
|
)
|
||||||
|
const controlsRef = useRef<OrbitControls | null>(null)
|
||||||
const wrapperRef = useRef<HTMLDivElement | null>(null)
|
const wrapperRef = useRef<HTMLDivElement | null>(null)
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
||||||
const animationRequestRef = useRef<number>()
|
const animationRequestRef = useRef<number>()
|
||||||
@ -168,8 +184,59 @@ export function ToastTextToCadSuccess({
|
|||||||
const ambientLight = new DirectionalLight(new Color('white'), 8.0)
|
const ambientLight = new DirectionalLight(new Color('white'), 8.0)
|
||||||
scene.add(ambientLight)
|
scene.add(ambientLight)
|
||||||
const camera = createCamera()
|
const camera = createCamera()
|
||||||
|
// Because this listener is registered before the OrbitControls are created,
|
||||||
|
// it runs first and can block the OrbitControls from working.
|
||||||
|
renderer.domElement.addEventListener('pointerdown', (e) => {
|
||||||
|
if (!controlsRef.current) return
|
||||||
|
const newInteractionType = getCameraInteractionType({
|
||||||
|
interactionGuards,
|
||||||
|
event: e,
|
||||||
|
})
|
||||||
|
console.log('newInteractionType', newInteractionType)
|
||||||
|
|
||||||
|
if (newInteractionType === 'none') {
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the OrbitControls to enable only the current interaction type.
|
||||||
|
* This is a hack to override the interaction types of the OrbitControls
|
||||||
|
* to match ours. In the future, we should roll our own class based on OrbitControls,
|
||||||
|
* which can handle interaction guards that are more complex than just mouse buttons.
|
||||||
|
*/
|
||||||
|
if (newInteractionType === 'pan') {
|
||||||
|
controlsRef.current.enablePan = true
|
||||||
|
controlsRef.current.enableZoom = false
|
||||||
|
controlsRef.current.enableRotate = false
|
||||||
|
controlsRef.current.mouseButtons = {
|
||||||
|
LEFT: MOUSE.PAN,
|
||||||
|
MIDDLE: MOUSE.PAN,
|
||||||
|
RIGHT: MOUSE.PAN,
|
||||||
|
}
|
||||||
|
} else if (newInteractionType === 'zoom') {
|
||||||
|
controlsRef.current.enablePan = false
|
||||||
|
controlsRef.current.enableZoom = true
|
||||||
|
controlsRef.current.enableRotate = false
|
||||||
|
controlsRef.current.mouseButtons = {
|
||||||
|
LEFT: MOUSE.DOLLY,
|
||||||
|
MIDDLE: MOUSE.DOLLY,
|
||||||
|
RIGHT: MOUSE.DOLLY,
|
||||||
|
}
|
||||||
|
} else if (newInteractionType === 'rotate') {
|
||||||
|
controlsRef.current.enablePan = false
|
||||||
|
controlsRef.current.enableZoom = false
|
||||||
|
controlsRef.current.enableRotate = true
|
||||||
|
controlsRef.current.mouseButtons = {
|
||||||
|
LEFT: MOUSE.ROTATE,
|
||||||
|
MIDDLE: MOUSE.ROTATE,
|
||||||
|
RIGHT: MOUSE.ROTATE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.update()
|
||||||
|
})
|
||||||
const controls = new OrbitControls(camera, renderer.domElement)
|
const controls = new OrbitControls(camera, renderer.domElement)
|
||||||
controls.enableDamping = true
|
controlsRef.current = controls
|
||||||
const loader = new GLTFLoader()
|
const loader = new GLTFLoader()
|
||||||
const dracoLoader = new DRACOLoader()
|
const dracoLoader = new DRACOLoader()
|
||||||
dracoLoader.setDecoderPath('/examples/jsm/libs/draco/')
|
dracoLoader.setDecoderPath('/examples/jsm/libs/draco/')
|
||||||
@ -270,7 +337,7 @@ export function ToastTextToCadSuccess({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-4 min-w-80" ref={wrapperRef}>
|
<div className="flex gap-4 min-w-80 user-select-none" ref={wrapperRef}>
|
||||||
<div
|
<div
|
||||||
className="flex-none overflow-hidden"
|
className="flex-none overflow-hidden"
|
||||||
style={{ width: CANVAS_SIZE + 'px', height: CANVAS_SIZE + 'px' }}
|
style={{ width: CANVAS_SIZE + 'px', height: CANVAS_SIZE + 'px' }}
|
||||||
@ -411,3 +478,22 @@ function traverseSceneToStyleObjects({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCameraInteractionType({
|
||||||
|
interactionGuards,
|
||||||
|
event,
|
||||||
|
}: {
|
||||||
|
interactionGuards: MouseGuard
|
||||||
|
event: MouseEvent
|
||||||
|
}): CameraInteractionType | 'none' {
|
||||||
|
if (interactionGuards.pan.callback(event)) {
|
||||||
|
return 'pan'
|
||||||
|
}
|
||||||
|
if (interactionGuards.zoom.dragCallback(event)) {
|
||||||
|
return 'zoom'
|
||||||
|
}
|
||||||
|
if (interactionGuards.rotate.callback(event)) {
|
||||||
|
return 'rotate'
|
||||||
|
}
|
||||||
|
return 'none'
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ const META =
|
|||||||
PLATFORM === 'macos' ? 'Cmd' : PLATFORM === 'windows' ? 'Win' : 'Super'
|
PLATFORM === 'macos' ? 'Cmd' : PLATFORM === 'windows' ? 'Win' : 'Super'
|
||||||
const ALT = PLATFORM === 'macos' ? 'Option' : 'Alt'
|
const ALT = PLATFORM === 'macos' ? 'Option' : 'Alt'
|
||||||
|
|
||||||
const noModifiersPressed = (e: React.MouseEvent) =>
|
const noModifiersPressed = (e: React.MouseEvent | MouseEvent) =>
|
||||||
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
|
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
|
||||||
|
|
||||||
export type CameraSystem =
|
export type CameraSystem =
|
||||||
@ -53,14 +53,14 @@ export function mouseControlsToCameraSystem(
|
|||||||
|
|
||||||
interface MouseGuardHandler {
|
interface MouseGuardHandler {
|
||||||
description: string
|
description: string
|
||||||
callback: (e: React.MouseEvent) => boolean
|
callback: (e: React.MouseEvent | MouseEvent) => boolean
|
||||||
lenientDragStartButton?: number
|
lenientDragStartButton?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MouseGuardZoomHandler {
|
interface MouseGuardZoomHandler {
|
||||||
description: string
|
description: string
|
||||||
dragCallback: (e: React.MouseEvent) => boolean
|
dragCallback: (e: React.MouseEvent | MouseEvent) => boolean
|
||||||
scrollCallback: (e: React.MouseEvent) => boolean
|
scrollCallback: (e: React.MouseEvent | MouseEvent) => boolean
|
||||||
lenientDragStartButton?: number
|
lenientDragStartButton?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ export interface MouseGuard {
|
|||||||
rotate: MouseGuardHandler
|
rotate: MouseGuardHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
export const btnName = (e: React.MouseEvent) => ({
|
export const btnName = (e: React.MouseEvent | MouseEvent) => ({
|
||||||
middle: !!(e.buttons & 4) || e.button === 1,
|
middle: !!(e.buttons & 4) || e.button === 1,
|
||||||
right: !!(e.buttons & 2) || e.button === 2,
|
right: !!(e.buttons & 2) || e.button === 2,
|
||||||
left: !!(e.buttons & 1) || e.button === 0,
|
left: !!(e.buttons & 1) || e.button === 0,
|
||||||
|
@ -16,6 +16,7 @@ import { commandBarMachine } from 'machines/commandBarMachine'
|
|||||||
import { getNextFileName } from './desktopFS'
|
import { getNextFileName } from './desktopFS'
|
||||||
import { reportRejection } from './trap'
|
import { reportRejection } from './trap'
|
||||||
import { toSync } from './utils'
|
import { toSync } from './utils'
|
||||||
|
import { CameraSystem } from './cameraControls'
|
||||||
|
|
||||||
export async function submitTextToCadPrompt(
|
export async function submitTextToCadPrompt(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
@ -77,6 +78,7 @@ interface TextToKclProps {
|
|||||||
settings: {
|
settings: {
|
||||||
theme: Themes
|
theme: Themes
|
||||||
highlightEdges: boolean
|
highlightEdges: boolean
|
||||||
|
mouseControls: CameraSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user