Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(events)!: pointerevents manager and state #529

Merged
merged 19 commits into from Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions playground/components.d.ts
Expand Up @@ -8,12 +8,14 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AnimatedModel: typeof import('./src/components/AnimatedModel.vue')['default']
Box: typeof import('./src/components/Box.vue')['default']
CameraOperator: typeof import('./src/components/CameraOperator.vue')['default']
Cameras: typeof import('./src/components/Cameras.vue')['default']
copy: typeof import('./src/components/TheBasic copy.vue')['default']
DanielTest: typeof import('./src/components/DanielTest.vue')['default']
DebugUI: typeof import('./src/components/DebugUI.vue')['default']
DeleteMe: typeof import('./src/components/DeleteMe.vue')['default']
EventsPropogation: typeof import('./src/components/EventsPropogation.vue')['default']
DynamicModel: typeof import('./src/components/DynamicModel.vue')['default']
FBXModels: typeof import('./src/components/FBXModels.vue')['default']
Gltf: typeof import('./src/components/gltf/index.vue')['default']
Expand Down
49 changes: 49 additions & 0 deletions playground/src/components/Box.vue
@@ -0,0 +1,49 @@

<script setup lang="ts">
import { ref, shallowRef, useAttrs } from 'vue'
import { useRenderLoop } from '@tresjs/core'
import { Color } from 'three'

const props = defineProps(['position', 'name'])

const boxRef = shallowRef()
const count = ref(0)

// Event Testing Colors
const black = new Color('black')
const green = new Color('green')
const red = new Color('red')
const blue = new Color('blue')
const yellow = new Color('yellow')
const white = new Color('white')
const purple = new Color('purple')
const cyan = new Color('cyan')

// Once the box has flashed green, lerp it back to black
const { onLoop } = useRenderLoop()
onLoop(() => {
boxRef.value?.material.color.lerp(black, 0.1)
})

// onClick flash the box green and update the counter
function handleClick(color: Color) {
boxRef.value.material.color.set(color)
count.value++
console.log(`Box ${boxRef.value.name} count=${count.value}`)
}
</script>

<template>
<TresMesh
ref="boxRef"
v-bind="props"
@click="handleClick(green)"
>
<TresBoxGeometry />
<TresMeshStandardMaterial />
<!-- <Text fontSize={0.5} font="monospace" position-z={0.501}>
{count}
</Text> -->
<slot />
</TresMesh>
</template>
187 changes: 187 additions & 0 deletions playground/src/pages/raycaster/Propagation.vue
alvarosabu marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,187 @@
<script setup lang="ts">
import {
TresCanvas,
} from '@tresjs/core'
import { BasicShadowMap, SRGBColorSpace, NoToneMapping, Mesh, BoxGeometry, MeshBasicMaterial } from 'three'
import { OrbitControls } from '@tresjs/cientos'
import '@tresjs/leches/styles'
import Box from '../../components/Box.vue'

// Create a box geometry and a basic material
const geometry = new BoxGeometry(1, 1, 1)
const material = new MeshBasicMaterial({ color: 0x00ff00 })

// Create a mesh with the geometry and material
const meshWithMaterial = new Mesh(geometry, material)

const gl = {
clearColor: '#202020',
shadows: true,
alpha: false,
shadowMapType: BasicShadowMap,
outputColorSpace: SRGBColorSpace,
toneMapping: NoToneMapping,
}
</script>

<template>
<TresCanvas
window-size
v-bind="gl"
>
<TresPerspectiveCamera
:position="[0, 0, 6]"
:look-at="[0, 0, 0]"
/>
<OrbitControls />

<TresDirectionalLight
:intensity="1"
:position="[1, 1, 1]"
/>
<TresAmbientLight :intensity="1" />
<primitive
:object="meshWithMaterial"
:position="[3, 1.5, 2]"
@click="event => event.object.material.color.set('red')"
/>
<Box
:position="[0, 1.5, 0]"
name="A0"
>
<Box
:position="[-0.66, -1, 0]"
name="B0"
>
<Box
:position="[-0.66, -1, 0]"
name="C0"
>
<Box
:position="[-0.66, -1, 0]"
name="D0"
/>
<Box
:position="[0.66, -1, 0]"
name="D1"
/>
</Box>
<Box
:position="[0.66, -1, 0]"
name="C1"
>
<Box
:position="[0.66, -1, 0]"
name="D2"
/>
</Box>
</Box>
<Box
:position="[0.66, -1, 0]"
name="B1"
>
<Box
:position="[0.66, -1, 0]"
name="C2"
>
<Box
:position="[0.66, -1, 0]"
name="D3"
/>
</Box>
</Box>
</Box>
<Box
:position="[0, 1.5, -3]"
name="A0"
>
<Box
:position="[-0.66, -1, 0]"
name="B0"
>
<Box
:position="[-0.66, -1, 0]"
name="C0"
>
<Box
:position="[-0.66, -1, 0]"
name="D0"
/>
<Box
:position="[0.66, -1, 0]"
name="D1"
/>
</Box>
<Box
:position="[0.66, -1, 0]"
name="C1"
>
<Box
:position="[0.66, -1, 0]"
name="D2"
/>
</Box>
</Box>
<Box
:position="[0.66, -1, 0]"
name="B1"
>
<Box
:position="[0.66, -1, 0]"
name="C2"
>
<Box
:position="[0.66, -1, 0]"
name="D3"
/>
</Box>
</Box>
</Box>
<Box
:position="[0, 1.5, -6]"
name="A0"
>
<Box
:position="[-0.66, -1, 0]"
name="B0"
>
<Box
:position="[-0.66, -1, 0]"
name="C0"
>
<Box
:position="[-0.66, -1, 0]"
name="D0"
/>
<Box
:position="[0.66, -1, 0]"
name="D1"
/>
</Box>
<Box
:position="[0.66, -1, 0]"
name="C1"
>
<Box
:position="[0.66, -1, 0]"
name="D2"
/>
</Box>
</Box>
<Box
:position="[0.66, -1, 0]"
name="B1"
>
<Box
:position="[0.66, -1, 0]"
name="C2"
>
<Box
:position="[0.66, -1, 0]"
name="D3"
/>
</Box>
</Box>
</Box>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/src/router.ts
Expand Up @@ -56,6 +56,11 @@ const routes = [
name: 'Raycaster',
component: () => import('./pages/raycaster/TheEvents.vue'),
},
{
path: '/raycaster/propagation',
name: 'Event Propogation',
component: () => import('./pages/raycaster/Propagation.vue'),
},
{
path: '/misc/text-3d',
name: 'Text3D',
Expand Down
23 changes: 21 additions & 2 deletions src/components/TresCanvas.vue
Expand Up @@ -25,6 +25,7 @@ import pkg from '../../package.json'
import {
useTresContextProvider,
usePointerEventHandler,
useEventStore,
useRenderLoop,
type TresContext,
} from '../composables'
Expand Down Expand Up @@ -69,7 +70,22 @@ const props = withDefaults(defineProps<TresCanvasProps>(), {
renderMode: 'always',
})

const emit = defineEmits(['render'])
// Define emits for Pointer events, pass `emit` into useEventStore so we can emit events off of TresCanvas
// Not sure of this solution, but you have to have emits defined on the component to emit them in vue
const emit = defineEmits([
'render',
'click',
'double-click',
'context-menu',
'pointer-move',
'pointer-up',
'pointer-down',
'pointer-enter',
'pointer-leave',
'pointer-over',
'pointer-out',
'wheel',
])

const canvas = ref<HTMLCanvasElement>()

Expand Down Expand Up @@ -124,6 +140,7 @@ const disableRender = computed(() => props.disableRender)
const context = shallowRef<TresContext | null>(null)

defineExpose({ context, dispose: () => dispose(context.value as TresContext, true) })

onMounted(() => {
const existingCanvas = canvas as Ref<HTMLCanvasElement>

Expand All @@ -136,7 +153,9 @@ onMounted(() => {
emit,
})

usePointerEventHandler(context.value)
// QUESTION: Maybe I should move the useEventStore logic into usePointerEventHandler? I seem to have created a similar pattern
// usePointerEventHandler({ scene: scene.value, contextParts: context.value })
useEventStore(scene.value, context.value, emit)

const { registerCamera, camera, cameras, deregisterCamera } = context.value

Expand Down
3 changes: 2 additions & 1 deletion src/composables/index.ts
Expand Up @@ -7,4 +7,5 @@ export * from './useRaycaster'
export * from './useLogger'
export * from './useSeek'
export * from './usePointerEventHandler'
export * from './useTresContextProvider'
export * from './useTresContextProvider'
export * from './useEventStore'