Selaa lähdekoodia

Merge pull request #26 from Tresjs/feature/25-extend-catalog-in-cientos

feat: extend catalog in cientos
Alvaro Saburido 2 vuotta sitten
vanhempi
commit
254bbc31cc

+ 30 - 26
packages/cientos/src/core/OrbitControls.vue

@@ -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>
 </script>
+
+<template>
+  <TresOrbitControls
+    v-if="camera && renderer"
+    ref="controls"
+    :args="[camera, renderer?.domElement]"
+    :enabling-dampling="enableDamping"
+  />
+</template>

+ 12 - 0
packages/cientos/src/core/useCientos.ts

@@ -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 - 0
packages/cientos/src/env.d.ts

@@ -1,3 +1,4 @@
+import { App } from 'vue'
 /// <reference types="vite/client" />
 /// <reference types="vite/client" />
 
 
 declare module '*.vue' {
 declare module '*.vue' {
@@ -6,3 +7,14 @@ declare module '*.vue' {
   const component: DefineComponent<{}, {}, any>
   const component: DefineComponent<{}, {}, any>
   export default component
   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
+    }
+  }
+}

+ 2 - 2
packages/tres/src/App.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 <script setup lang="ts">
 /* import { Color } from 'three' */
 /* import { Color } from 'three' */
-import { useTweakPane, OrbitControls } from '../../cientos/src'
+import { useTweakPane, OrbitControls, TransformControls } from '../../cientos/src'
 /* import TestSphere from '/@/components/TestSphere.vue' */
 /* import TestSphere from '/@/components/TestSphere.vue' */
 import Text3D from '/@/components/Text3D.vue'
 import Text3D from '/@/components/Text3D.vue'
 /* import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
 /* import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
@@ -25,8 +25,8 @@ useTweakPane()
       physically-correct-lights
       physically-correct-lights
     >
     >
       <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
       <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
-      <OrbitControls />
       <TresScene>
       <TresScene>
+        <OrbitControls />
         <TresAmbientLight :intensity="0.5" />
         <TresAmbientLight :intensity="0.5" />
         <!--  <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" /> -->
         <!--  <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" /> -->
         <Text3D />
         <Text3D />

+ 17 - 6
packages/tres/src/core/useCatalogue/index.ts

@@ -1,27 +1,38 @@
-import { useInstanceCreator } from '/@/core'
 import { App, ref, Component, Ref } from 'vue'
 import { App, ref, Component, Ref } from 'vue'
 import * as THREE from 'three'
 import * as THREE from 'three'
+import { useInstanceCreator } from '/@/core'
+import { useLogger } from '/@/composables'
 import { TresCatalogue } from '/@/types'
 import { TresCatalogue } from '/@/types'
 
 
-const catalogue: Ref<TresCatalogue> = ref({ ...THREE })
+const catalogue: Ref<TresCatalogue> = ref({ ...THREE, uuid: THREE.MathUtils.generateUUID() })
 
 
 delete catalogue.value.Scene
 delete catalogue.value.Scene
 
 
 let localApp: App
 let localApp: App
-
 export function useCatalogue(app?: App, prefix = 'Tres') {
 export function useCatalogue(app?: App, prefix = 'Tres') {
+  const { logMessage, logError } = useLogger()
   if (!localApp && app) {
   if (!localApp && app) {
     localApp = app
     localApp = app
   }
   }
   const { createComponentInstances } = useInstanceCreator(prefix)
   const { createComponentInstances } = useInstanceCreator(prefix)
 
 
   const extend = (objects: any) => {
   const extend = (objects: any) => {
+    if (!objects) {
+      logError('No objects provided to extend catalogue')
+      return
+    }
     catalogue.value = Object.assign(catalogue.value, objects)
     catalogue.value = Object.assign(catalogue.value, objects)
     const components = createComponentInstances(ref(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 {
   return {

+ 40 - 29
packages/tres/src/core/useInstanceCreator/index.ts

@@ -1,7 +1,7 @@
 /* eslint-disable new-cap */
 /* eslint-disable new-cap */
 /* eslint-disable @typescript-eslint/no-empty-function */
 /* 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 { isArray, isDefined, isFunction } from '@alvarosabu/utils'
 import { normalizeVectorFlexibleParam } from '/@/utils/normalize'
 import { normalizeVectorFlexibleParam } from '/@/utils/normalize'
 import { useCamera, useScene } from '/@/core/'
 import { useCamera, useScene } from '/@/core/'
@@ -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 {
     } 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,
      * Checks if the component has slots,
      * if it does, it will create a new Object3D instance passing the slots instances as properties
      * if it does, it will create a new Object3D instance passing the slots instances as properties
@@ -99,8 +106,8 @@ export function useInstanceCreator(prefix: string) {
      * const mesh = new Mesh(new BoxGeometry(), new MeshBasicMaterial())
      * const mesh = new Mesh(new BoxGeometry(), new MeshBasicMaterial())
      */
      */
     if (slots.default && slots?.default()) {
     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 {
     } else {
       // Creates a new THREE instance, if args is present, spread it on the constructor
       // Creates a new THREE instance, if args is present, spread it on the constructor
       return attrs.args ? new threeObj(...attrs.args) : new threeObj()
       return attrs.args ? new threeObj(...attrs.args) : new threeObj()
@@ -115,10 +122,12 @@ export function useInstanceCreator(prefix: string) {
         const cmp = defineComponent({
         const cmp = defineComponent({
           name,
           name,
           setup(props, { slots, attrs, ...ctx }) {
           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 { pushCamera } = useCamera()
 
 
-            const instance = createInstance(catalogue, threeObj, attrs, slots)
+            const instance = createInstance(threeObj, attrs, slots)
             processProps(attrs, instance)
             processProps(attrs, instance)
             // If the instance is a camera, push it to the camera stack
             // If the instance is a camera, push it to the camera stack
             if (instance instanceof PerspectiveCamera || instance instanceof OrthographicCamera) {
             if (instance instanceof PerspectiveCamera || instance instanceof OrthographicCamera) {
@@ -132,6 +141,8 @@ export function useInstanceCreator(prefix: string) {
 
 
             ctx.expose(instance)
             ctx.expose(instance)
             logMessage(name, {
             logMessage(name, {
+              sceneuuid: scene?.value.uuid,
+              catalogue: catalogue?.value.uuid,
               props,
               props,
               slots,
               slots,
               attrs,
               attrs,

+ 9 - 6
packages/tres/src/index.ts

@@ -1,10 +1,10 @@
-import { App, Component, watchEffect } from 'vue'
+import { App, Component } from 'vue'
 import { TresCanvas } from '/@/core/useRenderer/component'
 import { TresCanvas } from '/@/core/useRenderer/component'
 import { Scene } from '/@/core/useScene/component'
 import { Scene } from '/@/core/useScene/component'
 import { useCatalogue, useInstanceCreator } from '/@/core'
 import { useCatalogue, useInstanceCreator } from '/@/core'
 export * from '/@/core'
 export * from '/@/core'
 export * from './keys'
 export * from './keys'
-
+import { version } from '../package.json'
 export interface TresOptions {
 export interface TresOptions {
   prefix?: string
   prefix?: string
   extends?: Record<string, unknown>
   extends?: Record<string, unknown>
@@ -19,7 +19,9 @@ const plugin: TresPlugin = {
     const prefix = options?.prefix || 'Tres'
     const prefix = options?.prefix || 'Tres'
     app.component(`${prefix}Canvas`, TresCanvas)
     app.component(`${prefix}Canvas`, TresCanvas)
     app.component(`${prefix}Scene`, Scene)
     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 { createComponentInstances } = useInstanceCreator(prefix)
     const components = createComponentInstances(catalogue)
     const components = createComponentInstances(catalogue)
     /*  const components = createComponentInstances(
     /*  const components = createComponentInstances(
@@ -29,9 +31,10 @@ const plugin: TresPlugin = {
       app.component(key as string, cmp as Component)
       app.component(key as string, cmp as Component)
     })
     })
 
 
-    watchEffect(() => {
-      console.log({ catalogue })
-    })
+    window.__TRES__ = {
+      app,
+      version,
+    }
   },
   },
 }
 }
 
 

+ 1 - 6
packages/tres/src/main.ts

@@ -1,14 +1,9 @@
 import { createApp } from 'vue'
 import { createApp } from 'vue'
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
 import App from './App.vue'
 import App from './App.vue'
 import plugin from '.'
 import plugin from '.'
 import './style.css'
 import './style.css'
 
 
 export const app = createApp(App)
 export const app = createApp(App)
 
 
-app.use(plugin, {
-  extends: {
-    OrbitControls,
-  },
-})
+app.use(plugin)
 app.mount('#app')
 app.mount('#app')

+ 11 - 0
packages/tres/src/types/index.d.ts

@@ -11,3 +11,14 @@ export type TresVNodeType = VNodeTypes & {
 }
 }
 export type TresVNode = VNode & { children?: Array<VNode>; type: TresVNodeType }
 export type TresVNode = VNode & { children?: Array<VNode>; type: TresVNodeType }
 export type TresAttributes = Record<string, any> & { args?: number[] }
 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
+    }
+  }
+}