Skip to content

Commit

Permalink
feat: use devtool cb and perf stats from core
Browse files Browse the repository at this point in the history
  • Loading branch information
alvarosabu committed Dec 6, 2023
1 parent 29ff44d commit e35d546
Show file tree
Hide file tree
Showing 11 changed files with 782 additions and 434 deletions.
81 changes: 81 additions & 0 deletions client/components/Graph.vue
@@ -0,0 +1,81 @@
<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'
const props = withDefaults(defineProps<{
points: Array<number> // Array of y-values
value: number
unit: string
label: string
color: string
}>(),
{
points: () => [],
value: 0,
unit: '',
label: '',
color: 'green',
})
const width = 160
const height = 40
const strokeWidth = 2
// Determine the maximum value for scaling the graph
const maxValue = ref(140)
// Update maxValue to accommodate the range of y-values in points
watchEffect(() => {
const highestValue = Math.max(...props.points, 30) // Ensure at least 30
maxValue.value = Math.max(highestValue, maxValue.value)
})
const pointsF = computed(() => props.points.map(
(point, index) =>
`${index * strokeWidth},${height - (point * height / maxValue.value)}`,
).join(' '))
</script>

<template>
<div
class="
graph
relative
p-1
rounded
text-right
text-xs
outline-none
border-none
font-sans
"
>
<div class="absolute bottom-0.5 right-0.5 font-mono text-xs">
{{ Math.round(value) }} {{ unit }}
</div>
<svg
width="100%"
:height="height"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
:points="pointsF"
fill="none"
:stroke="color"
:stroke-width="strokeWidth"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</template>

<style>
.graph {
background-color: rgba(var(--nui-c-context), 0.1);
color: rgba(var(--nui-c-context), 1);
}
.graph polyline {
stroke: rgba(var(--nui-c-context), 1);
}
</style>
31 changes: 31 additions & 0 deletions client/components/Pane.vue
@@ -0,0 +1,31 @@
<script setup lang="ts">
defineProps<{
title: string
}>()
</script>

<template>
<div
class="relative
px-4
py-6
border
border-solid
border-gray-200
rounded
my-4"
>
<span
class="absolute
bg-white
text-xs
dark:bg-[#151515]
text-gray-400
px-2
rounded
-top-2
left-2"
>{{ title }}</span>
<slot />
</div>
</template>
86 changes: 86 additions & 0 deletions client/components/PerformanceMonitor.vue
@@ -0,0 +1,86 @@
<script setup lang="ts">
import { bytesToKB } from '../utils'
const { fps, memory, gl } = useDevtoolsHook()
</script>

<template>
<div class="grid grid-cols-2 gap-4">
<NCard
class="col-span-1"
n="green"
>
<Graph
:points="fps.accumulator"
:value="fps.value"
color="green"
n="green"
unit="FPS"
label="FPS"
/>
</NCard>
<NCard
class="col-span-1"
n="green"
>
<Graph
:points="memory.accumulator"
:value="memory.currentMem"
color="yellow"
n="yellow"
unit="MB"
label="memory"
/>
</NCard>
<Pane :title="`Memory ${bytesToKB(memory.allocatedMem)}KB`">
<div class="flex p4 justify-around w-full">
<div class="flex flex-col items-center gap-2">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.memory?.geometries || 0 }}
<i class="i-iconoir-box-3d-three-points" />
</div>
<span class="text-xs text-gray-500">Geometries</span>
</div>
<div class="flex flex-col items-center gap-2">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.memory?.textures || 0 }}
<i class="i-iconoir-select-face-3d" />
</div>
<span class="text-xs text-gray-500">Textures</span>
</div>
</div>
</Pane>
<Pane title="Render">
<div class="grid grid-cols-2 p4 justify-around w-full">
<div class="flex flex-col items-center gap-2 mb4">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.render?.calls || 0 }}
<i class="i-iconoir-comp-align-left" />
</div>
<span class="text-xs text-gray-500">Calls</span>
</div>
<div class="flex flex-col items-center gap-2 mb4">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.render?.triangles || 0 }}
<i class="i-iconoir-triangle" />
</div>
<span class="text-xs text-gray-500">Triangles</span>
</div>
<div class="flex flex-col items-center gap-2 mb4">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.render?.points || 0 }}
<i class="i-iconoir-one-point-circle" />
</div>
<span class="text-xs text-gray-500">Points</span>
</div>
<div class="flex flex-col items-center gap-2 mb4">
<div class="flex items-center font-mono gap-2">
{{ gl.renderer.info?.render?.lines || 0 }}
<i class="i-iconoir-linear" />
</div>
<span class="text-xs text-gray-500">Lines</span>
</div>
</div>
</Pane>
</div>
</template>
181 changes: 181 additions & 0 deletions client/composables/useDevtoolsHook.ts
@@ -0,0 +1,181 @@
import type { TresObject } from '@tresjs/core'
import type { Scene, WebGLRenderer } from 'three'
import { useTresContextProvider } from '@tresjs/core'
import type { SceneGraphObject } from '../types'
import { calculateMemoryUsage } from '../utils'
import { iants } from './../.nuxt/tailwind.config.d'

const scene = reactive({
objects: 0,
graph: {},
value: undefined as Scene | undefined,
})

const gl = {
fps: reactive({
value: 0,
accumulator: [],
lastLoggedTime: Date.now(),
logInterval: 1000,
}),
memory: reactive({
currentMem: 0,
averageMem: 0,
maxMemory: 0,
allocatedMem: 0,
accumulator: [],
lastLoggedTime: Date.now(),
logInterval: 1000,
}),
renderer: undefined as WebGLRenderer | undefined,
}

const icons: Record<string, string> = {
scene: 'i-carbon-web-services-container',
perspectivecamera: 'i-carbon-video',
mesh: 'i-carbon-cube',
group: 'i-carbon-group',
ambientlight: 'i-carbon-light',
directionallight: 'i-carbon-light',
spotlight: 'i-iconoir-project-curve-3d',
position: 'i-iconoir-axes',
rotation: 'i-carbon-rotate-clockwise',
scale: 'i-iconoir-ellipse-3d-three-points',
}

function createNode(object: TresObject) {
const node: SceneGraphObject = {
name: object.name,
type: object.type,
icon: icons[object.type.toLowerCase()] || 'i-carbon-cube',
position: {
x: object.position.x,
y: object.position.y,
z: object.position.z,
},
rotation: {
x: object.rotation.x,
y: object.rotation.y,
z: object.rotation.z,
},
children: [],
}

if (object.type === 'Mesh') {
node.material = object.material
node.geometry = object.geometry
node.scale = {
x: object.scale.x,
y: object.scale.y,
z: object.scale.z,
}
}

if (object.type.includes('Light')) {
node.color = object.color.getHexString()
node.intensity = object.intensity
}
return node
}

function getSceneGraph(scene: TresObject) {

function buildGraph(object: TresObject, node: SceneGraphObject) {
object.children.forEach((child: TresObject) => {
const childNode = createNode(child)
node.children.push(childNode)
buildGraph(child, childNode)
})
}

const root = createNode(scene)
buildGraph(scene, root)

return root
}

function countObjectsInScene(scene: Scene) {
let count = 0

scene.traverse((object) => {
// Check if the object is a 3D object
if (object.isObject3D) {
count++
}
})

return count
}

export function useDevtoolsHook() {
/* const updateInterval = 100 // Update interval in milliseconds
const fps = useFps({ every: updateInterval })
const { isSupported, memory } = useMemory({ interval: updateInterval })
const maxFrames = 160 */

// Connect with Core
const tresGlobalHook = {
cb(context: { renderer: Ref<WebGLRenderer>; scene: Ref<Scene> }) {
scene.value = context.scene.value
scene.objects = countObjectsInScene(context.scene.value)
gl.renderer = context.renderer.value
Object.assign(gl.fps, context.perf.fps)
gl.fps.accumulator = [...context.perf.fps.accumulator]
Object.assign(gl.memory, context.perf.memory)
gl.memory.accumulator = [...context.perf.memory.accumulator]
scene.graph = getSceneGraph(context.scene.value as unknown as TresObject)
},
}

window.parent.parent.__TRES__DEVTOOLS__ = tresGlobalHook

/* let lastUpdateTime = performance.now()

Check failure on line 132 in client/composables/useDevtoolsHook.ts

View workflow job for this annotation

GitHub Actions / Lint (16)

Expected indentation of 2 spaces but found 1
const updatePerformanceData = ({ timestamp }: { timestamp: number }) => {
// Update WebGL Memory Usage (Placeholder for actual logic)
// perf.memory.value = calculateMemoryUsage(gl)
if (scene.value) {
gl.memory.allocatedMem = calculateMemoryUsage(scene.value as unknown as TresObject)
}
// Update memory usage
if (timestamp - lastUpdateTime >= updateInterval) {
lastUpdateTime = timestamp
// Update FPS
gl.fps.accumulator.push(fps.value as never)
if (gl.fps.accumulator.length > maxFrames) {
gl.fps.accumulator.shift()
}
gl.fps.value = fps.value
// Update memory
if (isSupported.value && memory.value) {
gl.memory.accumulator.push(memory.value.usedJSHeapSize / 1024 / 1024 as never)
if (gl.memory.accumulator.length > maxFrames) {
gl.memory.accumulator.shift()
}
gl.memory.currentMem = gl.memory.accumulator.reduce((a, b) => a + b, 0) / gl.memory.accumulator.length
}
}
}
const { pause, resume } = useRafFn(updatePerformanceData, { immediate: true })
onUnmounted(() => {
pause()
}) */

return {
scene,
gl,
fps: gl.fps,
memory: gl.memory,
}
}

0 comments on commit e35d546

Please sign in to comment.