瀏覽代碼

Merge pull request #17 from Tresjs/feature/16-dynamically-extend-catalogue

Feature/16 dynamically extend catalogue
Alvaro Saburido 2 年之前
父節點
當前提交
02702e7bc9

+ 24 - 12
packages/tres/src/App.vue

@@ -1,25 +1,37 @@
 <script setup lang="ts">
-import { Color } from 'three'
+/* import { Color } from 'three' */
 import { useTweakPane, OrbitControls } from '../../cientos/src'
-import TestSphere from '/@/components/TestSphere.vue'
+/* import TestSphere from '/@/components/TestSphere.vue' */
+import Text3D from '/@/components/Text3D.vue'
+/* import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
+import { useTres, useCatalogue } from '/@/core' */
+
+/* const { extend } = useCatalogue() */
+
+/* extend({ OrbitControls }) */
 
-const colorTeal = new Color('teal')
 useTweakPane()
 
-const meshPosition = [0, 1, 0]
+/* const { state } = useTres() */
 </script>
 <template>
   <Suspense>
-    <TresCanvas shadows alpha power-preference="high-performance" preserve-drawing-buffer physically-correct-lights>
+    <TresCanvas
+      shadows
+      alpha
+      clear-color="teal"
+      power-preference="high-performance"
+      preserve-drawing-buffer
+      physically-correct-lights
+    >
       <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
+      <OrbitControls />
       <TresScene>
-        <OrbitControls />
-        <TresMesh :position="meshPosition" :scale="1">
-          <TresSphereGeometry />
-          <TresMeshToonMaterial :color="colorTeal" />
-        </TresMesh>
-        <TestSphere />
-        <TresAxesHelper :args="[1]" />
+        <TresAmbientLight :intensity="0.5" />
+        <!--  <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" /> -->
+        <Text3D />
+        <!--   <TestSphere /> -->
+        <TresAxesHelper :args="[1]" :visible="false" />
         <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
       </TresScene>
     </TresCanvas>

+ 41 - 0
packages/tres/src/components/Text3D.vue

@@ -0,0 +1,41 @@
+<script setup lang="ts">
+import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry'
+import { FontLoader } from 'three/examples/jsm/loaders/FontLoader'
+import { useCatalogue, useTexture } from '/@/core'
+const { extend } = useCatalogue()
+
+extend({ TextGeometry: TextGeometry })
+
+const fontPath = 'https://raw.githubusercontent.com/Tresjs/assets/main/fonts/FiraCodeRegular.json'
+
+const fontOptions = {
+  size: 0.5,
+  height: 0.2,
+  curveSegments: 5,
+  bevelEnabled: true,
+  bevelThickness: 0.05,
+  bevelSize: 0.02,
+  bevelOffset: 0,
+  bevelSegments: 4,
+}
+
+const loader = new FontLoader()
+
+const font = await new Promise((resolve, reject) => {
+  try {
+    loader.load(fontPath, font => {
+      resolve(font)
+    })
+  } catch (error) {
+    reject(console.error('cientos', error))
+  }
+})
+
+const matcapTexture = await useTexture(['https://raw.githubusercontent.com/Tresjs/assets/main/textures/matcaps/7.png'])
+</script>
+<template>
+  <TresMesh>
+    <TresTextGeometry :args="['TresJS', { font, ...fontOptions }]" center />
+    <TresMeshMatcapMaterial :matcap="matcapTexture" />
+  </TresMesh>
+</template>

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

@@ -1,14 +1,27 @@
+import { useInstanceCreator } from '/@/core'
+import { App, ref, Component, Ref } from 'vue'
 import * as THREE from 'three'
+import { TresCatalogue } from '/@/types'
 
-let catalogue: {
-  [key: string]: any
-} = { ...THREE }
+const catalogue: Ref<TresCatalogue> = ref({ ...THREE })
 
-delete catalogue.Scene
+delete catalogue.value.Scene
+
+let localApp: App
+
+export function useCatalogue(app?: App, prefix = 'Tres') {
+  if (!localApp && app) {
+    localApp = app
+  }
+  const { createComponentInstances } = useInstanceCreator(prefix)
 
-export function useCatalogue() {
   const extend = (objects: any) => {
-    catalogue = Object.assign(catalogue, objects)
+    catalogue.value = Object.assign(catalogue.value, objects)
+    const components = createComponentInstances(ref(objects))
+
+    components.forEach(([key, cmp]) => {
+      localApp.component(key as string, cmp as Component)
+    })
   }
 
   return {

+ 14 - 14
packages/tres/src/core/useInstanceCreator/index.ts

@@ -1,7 +1,7 @@
 /* eslint-disable new-cap */
 /* eslint-disable @typescript-eslint/no-empty-function */
 import { OrthographicCamera, PerspectiveCamera } from 'three'
-import { defineComponent } from 'vue'
+import { defineComponent, Ref } from 'vue'
 import { isArray, isDefined, isFunction } from '@alvarosabu/utils'
 import { normalizeVectorFlexibleParam } from '/@/utils/normalize'
 import { useCamera, useScene } from '/@/core/'
@@ -59,17 +59,17 @@ export function useInstanceCreator(prefix: string) {
     })
   }
 
-  function createInstanceFromVNode(vnode: TresVNode, catalogue: TresCatalogue): TresInstance {
+  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[vNodeType](...vnode.props.args)
+      internalInstance = new catalogue.value[vNodeType](...vnode.props.args)
     } else {
       // if args prop is not defined, create a new instance of catalogue[vNodeType] without arguments
-      internalInstance = new catalogue[vNodeType]()
+      internalInstance = new catalogue.value[vNodeType]()
     }
 
     // check if props is defined on the vnode
@@ -82,7 +82,7 @@ export function useInstanceCreator(prefix: string) {
   }
 
   function createInstance(
-    catalogue: Record<string, any>,
+    catalogue: Ref<TresCatalogue>,
     threeObj: any,
     attrs: TresAttributes,
     slots: Record<string, any>,
@@ -107,20 +107,14 @@ export function useInstanceCreator(prefix: string) {
     }
   }
 
-  function createComponentInstances(catalogue: Record<string, any>) {
-    return Object.entries(catalogue)
+  function createComponentInstances(catalogue: Ref<TresCatalogue>) {
+    return Object.entries(catalogue.value)
       .filter(([_key, value]) => (value as { prototype: any })?.prototype?.constructor?.toString().includes('class'))
       .map(([key, threeObj]) => {
         const name = `${prefix}${key}`
         const cmp = defineComponent({
           name,
           setup(props, { slots, attrs, ...ctx }) {
-            logMessage(name, {
-              props,
-              slots,
-              attrs,
-              ctx,
-            })
             const { scene } = useScene()
             const { pushCamera } = useCamera()
 
@@ -137,7 +131,13 @@ export function useInstanceCreator(prefix: string) {
             }
 
             ctx.expose(instance)
-
+            logMessage(name, {
+              props,
+              slots,
+              attrs,
+              ctx,
+              scene,
+            })
             return () => {}
           },
         })

+ 10 - 3
packages/tres/src/index.ts

@@ -1,4 +1,4 @@
-import { App, Component } from 'vue'
+import { App, Component, watchEffect } from 'vue'
 import { TresCanvas } from '/@/core/useRenderer/component'
 import { Scene } from '/@/core/useScene/component'
 import { useCatalogue, useInstanceCreator } from '/@/core'
@@ -19,12 +19,19 @@ const plugin: TresPlugin = {
     const prefix = options?.prefix || 'Tres'
     app.component(`${prefix}Canvas`, TresCanvas)
     app.component(`${prefix}Scene`, Scene)
-    const { catalogue } = useCatalogue()
+    const { catalogue } = useCatalogue(app, prefix)
     const { createComponentInstances } = useInstanceCreator(prefix)
-    const components = createComponentInstances(options?.extends ? { ...catalogue, ...options.extends } : catalogue)
+    const components = createComponentInstances(catalogue)
+    /*  const components = createComponentInstances(
+      options?.extends ? { ...catalogue, ...options.extends } : catalogue,
+    ) */
     components.forEach(([key, cmp]) => {
       app.component(key as string, cmp as Component)
     })
+
+    watchEffect(() => {
+      console.log({ catalogue })
+    })
   },
 }