Skip to content
This repository has been archived by the owner on Aug 18, 2024. It is now read-only.

Commit

Permalink
Split out examples and benchmarks routes, make scene loading logic a …
Browse files Browse the repository at this point in the history
…hook
  • Loading branch information
MichaelEstes committed Jun 12, 2024
1 parent d8e017f commit b7951a2
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react'

import { Entity } from '@etherealengine/ecs'
import { setVisibleComponent } from '@etherealengine/spatial/src/renderer/components/VisibleComponent'
import { AvatarBenchmark } from '../engine/benchmarks/AvatarBenchmark'
import { useRouteScene } from '../sceneRoute'

// let entities = [] as Entity[]
// let entitiesLength = 0
Expand Down Expand Up @@ -30,9 +29,9 @@ export const metadata = {
description: ''
}

export default function (props: { sceneEntity: Entity }) {
setVisibleComponent(props.sceneEntity, true)
return <AvatarBenchmark rootEntity={props.sceneEntity} onComplete={undefined as any} />
export default function () {
const sceneEntity = useRouteScene()
return sceneEntity.value ? <AvatarBenchmark rootEntity={sceneEntity.value} onComplete={undefined as any} /> : null
}

// export default function AvatarBenchmarking() {
Expand Down
28 changes: 28 additions & 0 deletions benchmarksRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'

import '@etherealengine/client-core/src/world/LocationModule'
import Routes, { RouteData } from './sceneRoute'

const prefix = './benchmarks/'

//@ts-ignore
const importedMetadata = import.meta.glob<any>('./benchmarks/*.tsx', {
import: 'metadata',
eager: true
})

//@ts-ignore
const imports = import.meta.glob<any>(`${prefix}*.tsx`)
const routes = Object.entries(imports).reduce(
(prev, [route, lazy]) => ({
...prev,
[route]: { page: React.lazy(lazy), metadata: importedMetadata[route] } as RouteData
}),
{}
) as Record<string, RouteData>

const BenchmarkRoutes = () => {
return <Routes routes={routes} prefix={prefix} header="Benchmarks" />
}

export default BenchmarkRoutes
8 changes: 7 additions & 1 deletion examples/avatarMocap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { encode } from 'msgpackr'
import React, { useEffect } from 'react'
import { Quaternion, Vector3 } from 'three'
import { useAvatarData } from '../engine/TestUtils'
import { useRouteScene } from '../sceneRoute'
import { spawnAvatar } from './utils/avatar/loadAvatarHelpers'
import { setupEntity } from './utils/common/entityUtils'

Expand Down Expand Up @@ -151,7 +152,7 @@ const ActivePoseUI = (props: { activePose: State<AvailablePoses> }) => {
)
}

export default function AvatarMocap(props: { sceneEntity: Entity }) {
function AvatarMocap(props: { sceneEntity: Entity }) {
setVisibleComponent(props.sceneEntity, true)
const rootUUID = useComponent(props.sceneEntity, UUIDComponent)
const network = useWorldNetwork()
Expand Down Expand Up @@ -229,3 +230,8 @@ export default function AvatarMocap(props: { sceneEntity: Entity }) {
</>
)
}

export default function () {
const sceneEntity = useRouteScene()
return sceneEntity.value ? <AvatarMocap sceneEntity={sceneEntity.value} /> : null
}
6 changes: 4 additions & 2 deletions examples/componentExamples.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Entity, setComponent } from '@etherealengine/ecs'
import React, { useEffect } from 'react'
import { ExamplesComponent } from '../engine/examples/ExamplesComponent'
import { useRouteScene } from '../sceneRoute'

export const metadata = {
title: 'Components Examples',
Expand All @@ -15,6 +16,7 @@ const ComponentExamples = (props: { sceneEntity: Entity }) => {
return null
}

export default function (props: { sceneEntity: Entity }) {
return <ComponentExamples sceneEntity={props.sceneEntity} />
export default function () {
const sceneEntity = useRouteScene()
return sceneEntity.value ? <ComponentExamples sceneEntity={sceneEntity.value} /> : null
}
11 changes: 7 additions & 4 deletions examples/gltf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TransformComponent } from '@etherealengine/spatial/src/transform/compon

import { Entity } from '@etherealengine/ecs'

import { useRouteScene } from '../sceneRoute'
import { useExampleEntity } from './utils/common/entityUtils'

export const metadata = {
Expand Down Expand Up @@ -79,8 +80,10 @@ const GLTF = (props: { sceneEntity: Entity }) => {
)
}

export default function GLTFViewer(props: { sceneEntity: Entity }) {
return (
export default function GLTFViewer() {
const sceneEntity = useRouteScene()

return sceneEntity.value ? (
<div
id="dnd-container"
style={{
Expand All @@ -94,8 +97,8 @@ export default function GLTFViewer(props: { sceneEntity: Entity }) {
}}
>
<DndWrapper id="dnd-container">
<GLTF sceneEntity={props.sceneEntity} />
<GLTF sceneEntity={sceneEntity.value} />
</DndWrapper>
</div>
)
) : null
}
159 changes: 7 additions & 152 deletions examplesRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,175 +1,30 @@
import React, { memo, useEffect, useRef, useState } from 'react'
import React from 'react'

import { useLoadEngineWithScene, useNetwork } from '@etherealengine/client-core/src/components/World/EngineHooks'
import { useLoadScene } from '@etherealengine/client-core/src/components/World/LoadLocationScene'
import '@etherealengine/client-core/src/world/LocationModule'
import { Engine, Entity, getComponent, setComponent } from '@etherealengine/ecs'
import { GLTFAssetState } from '@etherealengine/engine/src/gltf/GLTFState'
import { useHookstate, useImmediateEffect, useMutableState } from '@etherealengine/hyperflux'
import { CameraComponent } from '@etherealengine/spatial/src/camera/components/CameraComponent'
import { CameraOrbitComponent } from '@etherealengine/spatial/src/camera/components/CameraOrbitComponent'
import { NameComponent } from '@etherealengine/spatial/src/common/NameComponent'
import { InputComponent } from '@etherealengine/spatial/src/input/components/InputComponent'
import { RendererComponent } from '@etherealengine/spatial/src/renderer/WebGLRendererSystem'
import { useExampleEntity } from './examples/utils/common/entityUtils'

const buttonStyle = {
width: 'auto',
height: '100%',
fontSize: '1.5rem',
fontWeight: 'bold',
padding: '8px',
margin: '10px',
borderStyle: 'solid',
background: '#969696',
cursor: 'pointer',
boxShadow: '2px 2px 5px rgba(0, 0, 0, 0.3)', // Adds a slight 3D effect with a box-shadow
wordWrap: 'break-word',
borderColor: 'rgba(31, 27, 72, 0.85)' // Sets the outline color to rgb(31, 27, 72, 0.85)
} as React.CSSProperties

const Navbar = () => {
const navbarStyle = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '60px',
backgroundColor: '#1d2125',
color: '#e7e7e7'
}

const headingStyle = {
fontSize: '1.5rem',
fontWeight: 'bold'
}

return (
<div style={navbarStyle}>
<h1 style={headingStyle}>Examples</h1>
</div>
)
}
import Routes, { RouteData } from './sceneRoute'

const prefix = './examples/'
//@ts-ignore
const importedMetadata = import.meta.glob<any>(
[
'./examples/componentExamples.tsx',
'./examples/avatarBenchmark.tsx',
'./examples/avatarMocap.tsx',
'./examples/gltf.tsx'
],
['./examples/componentExamples.tsx', './examples/avatarMocap.tsx', './examples/gltf.tsx'],
{
import: 'metadata',
eager: true
}
)

type ExampleRouteData = {
metadata?: {
title?: string
description?: string
}
page: (...args: any[]) => any
}
//@ts-ignore
const imports = import.meta.glob<any>('./examples/*.tsx')
const routes = Object.entries(imports).reduce(
(prev, [route, lazy]) => ({
...prev,
[route]: { page: React.lazy(lazy), metadata: importedMetadata[route] } as ExampleRouteData
[route]: { page: React.lazy(lazy), metadata: importedMetadata[route] } as RouteData
}),
{}
) as Record<string, ExampleRouteData>

const ExampleScene = memo(
(props: { sceneEntity: Entity; route: string; example: React.FC<{ sceneEntity: Entity }> }) => {
const exampleEntity = useExampleEntity(props.sceneEntity)
setComponent(exampleEntity, NameComponent, props.route)

const Example = props.example
return <Example sceneEntity={exampleEntity} />
},
(prev, props) => {
return prev.route === props.route && prev.sceneEntity === props.sceneEntity
}
)
) as Record<string, RouteData>

const ExampleRoutes = () => {
const [currentRoute, setCurrentRoute] = useState('default')
const [page, setPage] = useState(null as null | ((...args: any[]) => any))

const ref = useRef(null as null | HTMLDivElement)
const projectName = 'ee-development-test-suite'
const sceneName = 'Examples.gltf'
useLoadScene({ projectName: projectName, sceneName: sceneName })
useNetwork({ online: false })
useLoadEngineWithScene()

const onClick = (route: string) => {
setCurrentRoute(route)
setPage(routes[route].page)
}

const gltfState = useMutableState(GLTFAssetState)
const sceneEntity = useHookstate<undefined | Entity>(undefined)

useEffect(() => {
const sceneURL = `projects/${projectName}/${sceneName}`
if (!gltfState[sceneURL].value) return
const entity = gltfState[sceneURL].value
if (entity) sceneEntity.set(entity)
}, [gltfState])

useEffect(() => {
if (!ref?.current) return

const canvas = getComponent(Engine.instance.viewerEntity, RendererComponent).renderer.domElement
canvas.parentElement?.removeChild(canvas)
ref.current.appendChild(canvas)

getComponent(Engine.instance.viewerEntity, RendererComponent).needsResize = true

const observer = new ResizeObserver(() => {
getComponent(Engine.instance.viewerEntity, RendererComponent).needsResize = true
})

observer.observe(ref.current)
return () => {
observer.disconnect()
}
}, [ref])

useImmediateEffect(() => {
const entity = Engine.instance.viewerEntity
setComponent(entity, CameraOrbitComponent)
setComponent(entity, InputComponent)
getComponent(entity, CameraComponent).position.set(0, 0, 4)
}, [])

return (
<>
<div style={{ display: 'flex', width: '100%', height: '100%', flexDirection: 'row' }}>
<div style={{ pointerEvents: 'all', overflow: 'auto', height: '100vh', width: '300px', background: '#2c2f33' }}>
<Navbar />
<div style={{ display: 'flex', flexDirection: 'column' }}>
{Object.entries(routes).map(([route, data]) => {
const pathTitle = route.replace('./examples/', '').replace('.tsx', '')
const title = data.metadata?.title ? data.metadata.title : pathTitle
return (
<button style={buttonStyle} key={pathTitle} onClick={() => onClick(route)}>
{title}
</button>
)
})}
</div>
</div>
<div id="examples-panel" ref={ref} style={{ flexGrow: 1, pointerEvents: 'none' }} />
</div>
{sceneEntity.value && page && (
<ExampleScene key={currentRoute} sceneEntity={sceneEntity.value} route={currentRoute} example={page} />
)}
</>
)
return <Routes routes={routes} prefix={prefix} header="Examples" />
}

export default ExampleRoutes
1 change: 1 addition & 0 deletions projectEventHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const avatarsFolder = path.resolve(__dirname, 'avatars')
const config = {
onInstall: async (app: Application) => {
await app.service('route-activate').create({ project: packageJson.name, route: '/examples', activate: true })
await app.service('route-activate').create({ project: packageJson.name, route: '/benchmarks', activate: true })
await installAvatarsFromProject(app, avatarsFolder)
}
} as ProjectEventHooks
Expand Down
Loading

0 comments on commit b7951a2

Please sign in to comment.