Skip to content

Commit

Permalink
Merge pull request #26 from Tresjs/feature/25-extend-catalog-in-cientos
Browse files Browse the repository at this point in the history
feat: extend catalog in cientos
  • Loading branch information
alvarosabu authored Dec 8, 2022
2 parents 6f95b4c + e1bfea1 commit 254bbc3
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 75 deletions.
56 changes: 30 additions & 26 deletions packages/cientos/src/core/OrbitControls.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
<script setup lang="ts">
import { useRenderLoop } from '@tresjs/core'
import { Camera, WebGLRenderer } from 'three'
import { OrbitControls as OrbitControlsImp } from 'three-stdlib'
import { inject, type Ref, unref, watch } from 'vue'
<script lang="ts" setup>
import { Camera, Vector3, WebGLRenderer } from 'three'
import { OrbitControls } from 'three-stdlib'
import { inject, ref, type Ref } from 'vue'
let controls: OrbitControlsImp
import { useCientos } from './useCientos'
const camera = inject<Ref<Camera>>('camera')
const renderer = inject<Ref<WebGLRenderer>>('renderer')
watch(
[camera, renderer],
() => {
if (camera?.value && renderer?.value) {
if (controls) controls.reset()
controls = new OrbitControlsImp(camera.value, unref(renderer).domElement)
controls.enableDamping = true
const { onLoop } = useRenderLoop()
onLoop(() => {
if (controls) {
controls.update()
}
})
}
},
const props = withDefaults(
defineProps<{
makeDefault?: boolean
camera?: Camera
domElement?: HTMLElement
target?: Ref<Vector3>
enableDamping?: boolean
}>(),
{
deep: true,
makeDefault: false,
},
)
const controls = ref(null)
const camera = inject<Ref<Camera>>('camera')
const renderer = inject<Ref<WebGLRenderer>>('renderer')
const { extend } = useCientos()
extend({ OrbitControls })
</script>

<template>
<TresOrbitControls
v-if="camera && renderer"
ref="controls"
:args="[camera, renderer?.domElement]"
:enabling-dampling="enableDamping"
/>
</template>
12 changes: 12 additions & 0 deletions packages/cientos/src/core/useCientos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { inject } from 'vue'

export function useCientos() {
const extend =
inject<(objects: any) => void>('extend') ||
(() => {
console.warn('No extend function provided')
})
return {
extend,
}
}
12 changes: 12 additions & 0 deletions packages/cientos/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { App } from 'vue'
/// <reference types="vite/client" />

declare module '*.vue' {
Expand All @@ -6,3 +7,14 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>
export default component
}

declare global {
// Define the window interface, with type annotations for the properties and methods of the window object
interface Window {
// Define the location property, with a type of Location
__TRES__: {
app: App
version: string
}
}
}
4 changes: 2 additions & 2 deletions packages/tres/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
/* import { Color } from 'three' */
import { useTweakPane, OrbitControls } from '../../cientos/src'
import { useTweakPane, OrbitControls, TransformControls } from '../../cientos/src'
/* import TestSphere from '/@/components/TestSphere.vue' */
import Text3D from '/@/components/Text3D.vue'
/* import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
Expand All @@ -25,8 +25,8 @@ useTweakPane()
physically-correct-lights
>
<TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
<OrbitControls />
<TresScene>
<OrbitControls />
<TresAmbientLight :intensity="0.5" />
<!-- <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" /> -->
<Text3D />
Expand Down
23 changes: 17 additions & 6 deletions packages/tres/src/core/useCatalogue/index.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
import { useInstanceCreator } from '/@/core'
import { App, ref, Component, Ref } from 'vue'
import * as THREE from 'three'
import { useInstanceCreator } from '/@/core'
import { useLogger } from '/@/composables'
import { TresCatalogue } from '/@/types'

const catalogue: Ref<TresCatalogue> = ref({ ...THREE })
const catalogue: Ref<TresCatalogue> = ref({ ...THREE, uuid: THREE.MathUtils.generateUUID() })

delete catalogue.value.Scene

let localApp: App

export function useCatalogue(app?: App, prefix = 'Tres') {
const { logMessage, logError } = useLogger()
if (!localApp && app) {
localApp = app
}
const { createComponentInstances } = useInstanceCreator(prefix)

const extend = (objects: any) => {
if (!objects) {
logError('No objects provided to extend catalogue')
return
}
catalogue.value = Object.assign(catalogue.value, objects)
const components = createComponentInstances(ref(objects))
logMessage('Adding objects to catalogue', { objects, catalogue: catalogue.value.uuid })

components.forEach(([key, cmp]) => {
localApp.component(key as string, cmp as Component)
})
if (localApp) {
components.forEach(([key, cmp]) => {
// If the component is not already registered, register it
if (!localApp._context.components[key as string]) {
localApp.component(key as string, cmp as Component)
}
})
}
}

return {
Expand Down
69 changes: 40 additions & 29 deletions packages/tres/src/core/useInstanceCreator/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable new-cap */
/* eslint-disable @typescript-eslint/no-empty-function */
import { OrthographicCamera, PerspectiveCamera } from 'three'
import { defineComponent, Ref } from 'vue'
import { OrthographicCamera, PerspectiveCamera, Scene } from 'three'
import { defineComponent, inject, Ref } from 'vue'
import { isArray, isDefined, isFunction } from '@alvarosabu/utils'
import { normalizeVectorFlexibleParam } from '/@/utils/normalize'
import { useCamera, useScene } from '/@/core/'
Expand Down Expand Up @@ -59,34 +59,41 @@ export function useInstanceCreator(prefix: string) {
})
}

function createInstanceFromVNode(vnode: TresVNode, catalogue: Ref<TresCatalogue>): TresInstance {
const vNodeType = ((vnode.type as TresVNodeType).name as string).replace(prefix, '')

// check if args prop is defined on the vnode
let internalInstance
if (vnode?.props?.args) {
// if args prop is defined, create new instance of catalogue[vNodeType] with the provided arguments
internalInstance = new catalogue.value[vNodeType](...vnode.props.args)
function createInstanceFromVNode(vnode: TresVNode): TresInstance | TresInstance[] {
const regex = /^Symbol\(Fragment\)$/g
// Check if the vnode is a Fragment
if (regex.test(vnode.type.toString())) {
return vnode.children.map(child => createInstanceFromVNode(child as TresVNode)) as TresInstance[]
} else {
// if args prop is not defined, create a new instance of catalogue[vNodeType] without arguments
internalInstance = new catalogue.value[vNodeType]()
}
const vNodeType = ((vnode.type as TresVNodeType).name as string).replace(prefix, '')
const catalogue = inject<Ref<TresCatalogue>>('catalogue')
// check if args prop is defined on the vnode
let internalInstance
if (catalogue) {
if (vnode?.props?.args) {
// if args prop is defined, create new instance of catalogue[vNodeType] with the provided arguments
if (catalogue?.value[vNodeType]) {
internalInstance = new catalogue.value[vNodeType](...vnode.props.args)
} else {
logError(`There is no ${vNodeType} in the catalogue`, catalogue?.value.uuid)
}
} else {
// if args prop is not defined, create a new instance of catalogue[vNodeType] without arguments
internalInstance = new catalogue.value[vNodeType]()
}
}

// check if props is defined on the vnode
if (vnode?.props) {
// if props is defined, process the props and pass the internalInstance to update its properties
processProps(vnode.props, internalInstance)
}
// check if props is defined on the vnode
if (vnode?.props) {
// if props is defined, process the props and pass the internalInstance to update its properties
processProps(vnode.props, internalInstance)
}

return internalInstance
return internalInstance
}
}

function createInstance(
catalogue: Ref<TresCatalogue>,
threeObj: any,
attrs: TresAttributes,
slots: Record<string, any>,
): TresInstance {
function createInstance(threeObj: any, attrs: TresAttributes, slots: Record<string, any>): TresInstance {
/*
* Checks if the component has slots,
* if it does, it will create a new Object3D instance passing the slots instances as properties
Expand All @@ -99,8 +106,8 @@ export function useInstanceCreator(prefix: string) {
* const mesh = new Mesh(new BoxGeometry(), new MeshBasicMaterial())
*/
if (slots.default && slots?.default()) {
const internal = slots.default().map((vnode: TresVNode) => createInstanceFromVNode(vnode, catalogue))
return new threeObj(...internal)
const internal = slots.default().map((vnode: TresVNode) => createInstanceFromVNode(vnode))
return new threeObj(...internal.flat())
} else {
// Creates a new THREE instance, if args is present, spread it on the constructor
return attrs.args ? new threeObj(...attrs.args) : new threeObj()
Expand All @@ -115,10 +122,12 @@ export function useInstanceCreator(prefix: string) {
const cmp = defineComponent({
name,
setup(props, { slots, attrs, ...ctx }) {
const { scene } = useScene()
const { scene: fallback } = useScene()
const scene = inject<Ref<Scene>>('local-scene') || fallback
const catalogue = inject<Ref<TresCatalogue>>('catalogue')
const { pushCamera } = useCamera()

const instance = createInstance(catalogue, threeObj, attrs, slots)
const instance = createInstance(threeObj, attrs, slots)
processProps(attrs, instance)
// If the instance is a camera, push it to the camera stack
if (instance instanceof PerspectiveCamera || instance instanceof OrthographicCamera) {
Expand All @@ -132,6 +141,8 @@ export function useInstanceCreator(prefix: string) {

ctx.expose(instance)
logMessage(name, {
sceneuuid: scene?.value.uuid,
catalogue: catalogue?.value.uuid,
props,
slots,
attrs,
Expand Down
15 changes: 9 additions & 6 deletions packages/tres/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { App, Component, watchEffect } from 'vue'
import { App, Component } from 'vue'
import { TresCanvas } from '/@/core/useRenderer/component'
import { Scene } from '/@/core/useScene/component'
import { useCatalogue, useInstanceCreator } from '/@/core'
export * from '/@/core'
export * from './keys'

import { version } from '../package.json'
export interface TresOptions {
prefix?: string
extends?: Record<string, unknown>
Expand All @@ -19,7 +19,9 @@ const plugin: TresPlugin = {
const prefix = options?.prefix || 'Tres'
app.component(`${prefix}Canvas`, TresCanvas)
app.component(`${prefix}Scene`, Scene)
const { catalogue } = useCatalogue(app, prefix)
const { catalogue, extend } = useCatalogue(app, prefix)
app.provide('catalogue', catalogue)
app.provide('extend', extend)
const { createComponentInstances } = useInstanceCreator(prefix)
const components = createComponentInstances(catalogue)
/* const components = createComponentInstances(
Expand All @@ -29,9 +31,10 @@ const plugin: TresPlugin = {
app.component(key as string, cmp as Component)
})

watchEffect(() => {
console.log({ catalogue })
})
window.__TRES__ = {
app,
version,
}
},
}

Expand Down
7 changes: 1 addition & 6 deletions packages/tres/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { createApp } from 'vue'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import App from './App.vue'
import plugin from '.'
import './style.css'

export const app = createApp(App)

app.use(plugin, {
extends: {
OrbitControls,
},
})
app.use(plugin)
app.mount('#app')
11 changes: 11 additions & 0 deletions packages/tres/src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ export type TresVNodeType = VNodeTypes & {
}
export type TresVNode = VNode & { children?: Array<VNode>; type: TresVNodeType }
export type TresAttributes = Record<string, any> & { args?: number[] }

declare global {
// Define the window interface, with type annotations for the properties and methods of the window object
interface Window {
// Define the location property, with a type of Location
__TRES__: {
app: App
version: string
}
}
}

0 comments on commit 254bbc3

Please sign in to comment.