Skip to content

Commit

Permalink
Loading Notification (#1026)
Browse files Browse the repository at this point in the history
  • Loading branch information
HunterBarclay authored Jul 19, 2024
2 parents f7ca1c9 + ddfde70 commit 94839ef
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 30 deletions.
13 changes: 13 additions & 0 deletions fission/src/Synthesis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import ImportLocalMirabufModal from "@/modals/mirabuf/ImportLocalMirabufModal.ts
import APS from "./aps/APS.ts"
import ImportMirabufPanel from "@/ui/panels/mirabuf/ImportMirabufPanel.tsx"
import Skybox from "./ui/components/Skybox.tsx"
import ProgressNotifications from "./ui/components/ProgressNotification.tsx"
import { ProgressHandle } from "./ui/components/ProgressNotificationData.ts"
import ConfigureRobotModal from "./ui/modals/configuring/ConfigureRobotModal.tsx"
import ResetAllInputsModal from "./ui/modals/configuring/ResetAllInputsModal.tsx"
import ZoneConfigPanel from "./ui/panels/configuring/scoring/ZoneConfigPanel.tsx"
Expand Down Expand Up @@ -107,12 +109,17 @@ function Synthesis() {
}

const setup = async () => {
const setupProgress = new ProgressHandle("Spawning Default Robot")
setupProgress.Update("Checking cache...", 0.1)

const info = await MirabufCachingService.CacheRemote(mira_path, MiraType.ROBOT)
.catch(_ => MirabufCachingService.CacheRemote(DEFAULT_MIRA_PATH, MiraType.ROBOT))
.catch(console.error)

const miraAssembly = await MirabufCachingService.Get(info!.id, MiraType.ROBOT)

setupProgress.Update("Parsing assembly...", 0.5)

await (async () => {
if (!miraAssembly || !(miraAssembly instanceof mirabuf.Assembly)) {
return
Expand All @@ -121,11 +128,16 @@ function Synthesis() {
const parser = new MirabufParser(miraAssembly)
if (parser.maxErrorSeverity >= ParseErrorSeverity.Unimportable) {
console.error(`Assembly Parser produced significant errors for '${miraAssembly.info!.name!}'`)
setupProgress.Fail("Failed to parse assembly")
return
}

setupProgress.Update("Creating scene object...", 0.9)

const mirabufSceneObject = new MirabufSceneObject(new MirabufInstance(parser), miraAssembly.info!.name!)
World.SceneRenderer.RegisterSceneObject(mirabufSceneObject)

setupProgress.Done()
})()
}

Expand Down Expand Up @@ -186,6 +198,7 @@ function Synthesis() {
{modalElement}
</div>
)}
<ProgressNotifications key={"progress-notifications"} />
<ToastContainer key={"toast-container"} />
</ToastProvider>
</PanelControlProvider>
Expand Down
10 changes: 5 additions & 5 deletions fission/src/mirabuf/MirabufInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as THREE from "three"
import { mirabuf } from "../proto/mirabuf"
import MirabufParser, { ParseErrorSeverity } from "./MirabufParser.ts"
import World from "@/systems/World.ts"
import { ProgressHandle } from "@/ui/components/ProgressNotificationData.ts"

type MirabufPartInstanceGUID = string

Expand Down Expand Up @@ -107,7 +108,7 @@ class MirabufInstance {
return this._batches
}

public constructor(parser: MirabufParser, materialStyle?: MaterialStyle) {
public constructor(parser: MirabufParser, materialStyle?: MaterialStyle, progressHandle?: ProgressHandle) {
if (parser.errors.some(x => x[0] >= ParseErrorSeverity.Unimportable)) {
throw new Error("Parser has significant errors...")
}
Expand All @@ -117,7 +118,10 @@ class MirabufInstance {
this._meshes = new Map()
this._batches = new Array<THREE.BatchedMesh>()

progressHandle?.Update("Loading materials...", 0.4)
this.LoadMaterials(materialStyle ?? MaterialStyle.Regular)

progressHandle?.Update("Creating meshes...", 0.5)
this.CreateMeshes()
}

Expand Down Expand Up @@ -236,8 +240,6 @@ class MirabufInstance {
const batchedMesh = new THREE.BatchedMesh(count.maxInstances, count.maxVertices, count.maxIndices)
this._batches.push(batchedMesh)

console.debug(`${count.maxInstances}, ${count.maxVertices}, ${count.maxIndices}`)

batchedMesh.material = material
batchedMesh.castShadow = true
batchedMesh.receiveShadow = true
Expand All @@ -253,8 +255,6 @@ class MirabufInstance {

batchedMesh.setMatrixAt(geoId, mat)

console.debug(geoId)

let bodies = this._meshes.get(instance.info!.GUID!)
if (!bodies) {
bodies = new Array<[THREE.BatchedMesh, number]>()
Expand Down
5 changes: 4 additions & 1 deletion fission/src/mirabuf/MirabufParser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from "three"
import { mirabuf } from "@/proto/mirabuf"
import { MirabufTransform_ThreeMatrix4 } from "@/util/TypeConversions"
import { ProgressHandle } from "@/ui/components/ProgressNotificationData"

export type RigidNodeId = string

Expand Down Expand Up @@ -72,11 +73,13 @@ class MirabufParser {
return this._rootNode
}

public constructor(assembly: mirabuf.Assembly) {
public constructor(assembly: mirabuf.Assembly, progressHandle?: ProgressHandle) {
this._assembly = assembly
this._errors = new Array<ParseError>()
this._globalTransforms = new Map()

progressHandle?.Update("Parsing assembly...", 0.3)

this.GenerateTreeValues()
this.LoadGlobalTransforms()

Expand Down
14 changes: 10 additions & 4 deletions fission/src/mirabuf/MirabufSceneObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
import { MiraType } from "./MirabufLoader"
import IntakeSensorSceneObject from "./IntakeSensorSceneObject"
import EjectableSceneObject from "./EjectableSceneObject"
import { ProgressHandle } from "@/ui/components/ProgressNotificationData"

const DEBUG_BODIES = false

Expand Down Expand Up @@ -80,12 +81,14 @@ class MirabufSceneObject extends SceneObject {
return this._mirabufInstance.parser.rootNode
}

public constructor(mirabufInstance: MirabufInstance, assemblyName: string) {
public constructor(mirabufInstance: MirabufInstance, assemblyName: string, progressHandle?: ProgressHandle) {
super()

this._mirabufInstance = mirabufInstance
this._assemblyName = assemblyName

progressHandle?.Update("Creating mechanism...", 0.9)

this._mechanism = World.PhysicsSystem.CreateMechanismFromParser(this._mirabufInstance.parser)
if (this._mechanism.layerReserve) {
this._physicsLayerReserve = this._mechanism.layerReserve
Expand Down Expand Up @@ -366,14 +369,17 @@ class MirabufSceneObject extends SceneObject {
}
}

export async function CreateMirabuf(assembly: mirabuf.Assembly): Promise<MirabufSceneObject | null | undefined> {
const parser = new MirabufParser(assembly)
export async function CreateMirabuf(
assembly: mirabuf.Assembly,
progressHandle?: ProgressHandle
): Promise<MirabufSceneObject | null | undefined> {
const parser = new MirabufParser(assembly, progressHandle)
if (parser.maxErrorSeverity >= ParseErrorSeverity.Unimportable) {
console.error(`Assembly Parser produced significant errors for '${assembly.info!.name!}'`)
return
}

return new MirabufSceneObject(new MirabufInstance(parser), assembly.info!.name!)
return new MirabufSceneObject(new MirabufInstance(parser), assembly.info!.name!, progressHandle)
}

/**
Expand Down
4 changes: 3 additions & 1 deletion fission/src/test/PhysicsSystem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ describe("Mirabuf Physics Loading", () => {
const assembly = await MirabufCachingService.CacheRemote(
"/api/mira/Robots/Team 2471 (2018)_v7.mira",
MiraType.ROBOT
).then(x => MirabufCachingService.Get(x!.id, MiraType.ROBOT))
).then(x => {
return MirabufCachingService.Get(x!.id, MiraType.ROBOT)
})

const parser = new MirabufParser(assembly!)
const physSystem = new PhysicsSystem()
Expand Down
155 changes: 155 additions & 0 deletions fission/src/ui/components/ProgressNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { styled, Typography } from "@mui/material"
import { Box } from "@mui/system"
import { useEffect, useReducer, useState } from "react"
import { ProgressHandle, ProgressHandleStatus, ProgressEvent } from "./ProgressNotificationData"
import { easeOutQuad } from "@/util/EasingFunctions"

interface ProgressData {
lastValue: number
currentValue: number
lastUpdate: number
}

const handleMap = new Map<number, ProgressHandle>()

const TypoStyled = styled(Typography)(_ => ({
fontFamily: "Artifakt",
textAlign: "center",
}))

interface NotificationProps {
handle: ProgressHandle
}

function Interp(elapse: number, progressData: ProgressData) {
const [value, setValue] = useState<number>(0)

useEffect(() => {
const update = () => {
// Get the portion of the completed elapse timer, passed into an easing function.
const n = Math.min(1.0, Math.max(0.0, (Date.now() - progressData.lastUpdate) / elapse))
// Convert the result of the easing function [0, 1] to a lerp from last value to current value
const v = progressData.lastValue + (progressData.currentValue - progressData.lastValue) * easeOutQuad(n)

setValue(v)
}

const interval = setInterval(update, 5)
const timeout = setTimeout(() => clearInterval(interval), elapse)

return () => {
clearTimeout(timeout)
clearInterval(interval)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [progressData])

return value
}

function ProgressNotification({ handle }: NotificationProps) {
const [progressData, setProgressData] = useState<ProgressData>({
lastValue: 0,
currentValue: 0,
lastUpdate: Date.now(),
})

const interpProgress = Interp(500, progressData)

useEffect(() => {
setProgressData({ lastValue: progressData.currentValue, currentValue: handle.progress, lastUpdate: Date.now() })
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [handle.progress])

return (
<Box
key={handle.handleId}
component={"div"}
display={"flex"}
flexDirection={"column"}
sx={{
backgroundColor: "#000000",
borderWidth: "0rem",
borderRadius: "0.5rem",
overflow: "hidden",
}}
>
<Box
component={"div"}
display={"flex"}
flexDirection={"column"}
sx={{
paddingY: "0.75rem",
paddingX: "1.5rem",
}}
>
<TypoStyled fontWeight={"700"} fontSize={"1rem"}>
{handle.title}
</TypoStyled>
{handle.message.length > 0 ? <TypoStyled fontSize={"0.75rem"}>{handle.message}</TypoStyled> : <></>}
</Box>
<Box
key={"bar"}
component={"div"}
sx={{
backgroundColor:
handle.status == ProgressHandleStatus.inProgress
? "#ffc21a" // Autodesk Gold
: handle.status == ProgressHandleStatus.Done
? "#2bc275" // Autodesk Plant
: "#d74e26", // Autodesk Clay
bottom: "0pt",
left: "0pt",
width: `${interpProgress * 100}%`,
height: "0.5rem",
}}
/>
</Box>
)
}

function ProgressNotifications() {
const [progressElements, updateProgressElements] = useReducer(() => {
return handleMap.size > 0
? [...handleMap.entries()].map(([_, handle]) => (
<ProgressNotification handle={handle} key={handle.handleId} />
))
: undefined
}, undefined)

useEffect(() => {
const onHandleUpdate = (e: ProgressEvent) => {
const handle = e.handle
if (handle.status > 0) {
setTimeout(() => handleMap.delete(handle.handleId) && updateProgressElements(), 2000)
}
handleMap.set(handle.handleId, handle)
updateProgressElements()
}

ProgressEvent.AddListener(onHandleUpdate)
return () => {
ProgressEvent.RemoveListener(onHandleUpdate)
}
}, [updateProgressElements])

return (
<Box
component={"div"}
display={"flex"}
position={"fixed"}
sx={{
bottom: "0.5rem",
left: "50vw",
transform: "translate(-50%, 0)",
maxWidth: "50vw",
flexWrap: "wrap",
gap: "0.5rem",
}}
>
{progressElements ?? <></>}
</Box>
)
}

export default ProgressNotifications
Loading

0 comments on commit 94839ef

Please sign in to comment.