Skip to content

Commit ae8e477

Browse files
Merge branch 'dev' into ryan/1925/camera-implementation
2 parents 62a3fa4 + 90319aa commit ae8e477

28 files changed

+259
-276
lines changed

fission/forge.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { ForgeConfig } from "@electron-forge/shared-types"
1+
import { FuseV1Options, FuseVersion } from "@electron/fuses"
22
import { MakerSquirrel } from "@electron-forge/maker-squirrel"
33
import { MakerZIP } from "@electron-forge/maker-zip"
4-
import { VitePlugin } from "@electron-forge/plugin-vite"
54
import { FusesPlugin } from "@electron-forge/plugin-fuses"
6-
import { FuseV1Options, FuseVersion } from "@electron/fuses"
5+
import { VitePlugin } from "@electron-forge/plugin-vite"
6+
import type { ForgeConfig } from "@electron-forge/shared-types"
77
import path from "path"
88

99
const config: ForgeConfig = {

fission/src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { app, BrowserWindow } from "electron"
21
import path from "node:path"
2+
import { app, BrowserWindow } from "electron"
33
import started from "electron-squirrel-startup"
44

55
// Handle creating/removing shortcuts on Windows when installing/uninstalling.

fission/src/mirabuf/EjectableSceneObject.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,7 @@ class EjectableSceneObject extends SceneObject {
8080
World.physicsSystem.disablePhysicsForBody(this._gamePieceBodyId)
8181

8282
// Remove from any scoring zones
83-
const zones = [...World.sceneRenderer.sceneObjects.entries()]
84-
.filter(x => x[1] instanceof ScoringZoneSceneObject)
85-
.map(x => x[1]) as ScoringZoneSceneObject[]
86-
83+
const zones = World.sceneRenderer.filterSceneObjects(x => x instanceof ScoringZoneSceneObject)
8784
zones.forEach(x => {
8885
if (this._gamePieceBodyId) ScoringZoneSceneObject.removeGamepiece(x, this._gamePieceBodyId)
8986
})

fission/src/mirabuf/MirabufInstance.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ import { ParseErrorSeverity } from "./MirabufParser.ts"
88
type MirabufPartInstanceGUID = string
99

1010
const WIREFRAME = false
11+
const CHROME_VERSION_FOR_INSTANCED_MESH = 139
12+
13+
const detectInstancedMeshSupport = (): boolean => {
14+
const userAgent = navigator.userAgent
15+
const chromeMatch = userAgent.match(/Chrome\/(\d+)/)
16+
17+
if (chromeMatch) {
18+
const chromeVersion = parseInt(chromeMatch[1], 10)
19+
console.log(
20+
`Detected Chrome ${chromeVersion}, using ${chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH ? "InstancedMesh" : "BatchedMesh"}`
21+
)
22+
return chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH
23+
}
24+
25+
console.log(`Non-Chrome browser detected (${userAgent}), using BatchedMesh`)
26+
return false
27+
}
28+
29+
const USE_INSTANCED_MESH = detectInstancedMeshSupport()
1130

1231
export enum MaterialStyle {
1332
REGULAR = 0,
@@ -93,8 +112,8 @@ const transformGeometry = (geometry: THREE.BufferGeometry, mesh: mirabuf.IMesh)
93112
class MirabufInstance {
94113
private _mirabufParser: MirabufParser
95114
private _materials: Map<string, THREE.Material>
96-
private _meshes: Map<MirabufPartInstanceGUID, Array<[THREE.BatchedMesh, number]>>
97-
private _batches: Array<THREE.BatchedMesh>
115+
private _meshes: Map<MirabufPartInstanceGUID, Array<[THREE.InstancedMesh | THREE.BatchedMesh, number]>>
116+
private _batches: Array<THREE.InstancedMesh | THREE.BatchedMesh>
98117

99118
public get parser() {
100119
return this._mirabufParser
@@ -160,6 +179,63 @@ class MirabufInstance {
160179
* Creates ThreeJS meshes from the parsed mirabuf file.
161180
*/
162181
private createMeshes() {
182+
if (USE_INSTANCED_MESH) {
183+
this.createInstancedMeshes()
184+
} else {
185+
this.createBatchedMeshes()
186+
}
187+
}
188+
189+
/**
190+
* Creates InstancedMesh objects, as newer version of Chrome break with BatchedMesh
191+
*/
192+
private createInstancedMeshes() {
193+
const assembly = this._mirabufParser.assembly
194+
const instances = assembly.data!.parts!.partInstances!
195+
196+
Object.values(instances).forEach(instance => {
197+
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]
198+
const bodies = definition?.bodies ?? []
199+
200+
bodies.forEach(body => {
201+
const mesh = body?.triangleMesh?.mesh
202+
if (!mesh?.verts || !mesh.normals || !mesh.uv || !mesh.indices) return
203+
204+
const appearanceOverride = body.appearanceOverride
205+
const material = WIREFRAME
206+
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
207+
: appearanceOverride && this._materials.has(appearanceOverride)
208+
? this._materials.get(appearanceOverride)!
209+
: fillerMaterials[nextFillerMaterial++ % fillerMaterials.length]
210+
211+
const geometry = new THREE.BufferGeometry()
212+
transformGeometry(geometry, mesh)
213+
214+
// Create InstancedMesh with count of 1 for this body
215+
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1)
216+
instancedMesh.castShadow = true
217+
instancedMesh.receiveShadow = true
218+
219+
const mat = this._mirabufParser.globalTransforms.get(instance.info!.GUID!)!
220+
instancedMesh.setMatrixAt(0, mat)
221+
instancedMesh.instanceMatrix.needsUpdate = true
222+
223+
this._batches.push(instancedMesh)
224+
225+
let bodies = this._meshes.get(instance.info!.GUID!)
226+
if (!bodies) {
227+
bodies = []
228+
this._meshes.set(instance.info!.GUID!, bodies)
229+
}
230+
bodies.push([instancedMesh, 0])
231+
})
232+
})
233+
}
234+
235+
/**
236+
* Creates BatchedMesh, more efficient, but broken in newer versions of Chrome
237+
*/
238+
private createBatchedMeshes() {
163239
const assembly = this._mirabufParser.assembly
164240
const instances = assembly.data!.parts!.partInstances!
165241

@@ -171,6 +247,7 @@ class MirabufInstance {
171247

172248
const batchMap = new Map<THREE.Material, Map<string, [mirabuf.IBody, Array<mirabuf.IPartInstance>]>>()
173249
const countMap = new Map<THREE.Material, BatchCounts>()
250+
174251
// Filter all instances by first material, then body
175252
Object.values(instances).forEach(instance => {
176253
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]
@@ -180,7 +257,6 @@ class MirabufInstance {
180257
if (!mesh?.verts || !mesh.normals || !mesh.uv || !mesh.indices) return
181258

182259
const appearanceOverride = body.appearanceOverride
183-
184260
const material = WIREFRAME
185261
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
186262
: appearanceOverride && this._materials.has(appearanceOverride)

fission/src/mirabuf/MirabufSceneObject.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,13 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
471471
.clone()
472472
.premultiply(transform)
473473
const meshes = this._mirabufInstance.meshes.get(part) ?? []
474-
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
474+
meshes.forEach(([mesh, index]) => {
475+
mesh.setMatrixAt(index, partTransform)
476+
// Only update instanceMatrix for InstancedMesh
477+
if ("instanceMatrix" in mesh) {
478+
mesh.instanceMatrix.needsUpdate = true
479+
}
480+
})
475481
})
476482
}
477483

fission/src/systems/World.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ class World {
119119
World._analyticsSystem?.update(this._currentDeltaT)
120120
World._performanceMonitorSystem?.update(this._currentDeltaT)
121121

122-
RobotDimensionTracker.update(World._sceneRenderer)
123-
RobotPositionTracker.update(World._sceneRenderer)
122+
RobotDimensionTracker.update()
123+
RobotPositionTracker.update()
124124
}
125125

126126
public static get currentDeltaT(): number {

fission/src/systems/match_mode/DefaultMatchModeConfigs.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ class DefaultMatchModeConfigs {
6767
}
6868
}
6969

70+
static fallbackValues = (): MatchModeConfig => {
71+
return {
72+
id: "default",
73+
name: "Default",
74+
isDefault: true,
75+
autonomousTime: 15,
76+
teleopTime: 135,
77+
endgameTime: 20,
78+
ignoreRotation: true,
79+
maxHeight: Infinity,
80+
heightLimitPenalty: 2,
81+
sideMaxExtension: Infinity,
82+
sideExtensionPenalty: 2,
83+
}
84+
}
85+
7086
/** @returns {MatchModeConfig[]} New copies of the default match mode configs without reference to any others. */
7187
public static get defaultMatchModeConfigCopies(): MatchModeConfig[] {
7288
return [

fission/src/systems/match_mode/MatchMode.ts

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,13 @@ import beep from "@/assets/sound-files/beep.wav"
22
import MatchEnd from "@/assets/sound-files/MatchEnd.wav"
33
import MatchResume from "@/assets/sound-files/MatchResume.wav"
44
import MatchStart from "@/assets/sound-files/MatchStart.wav"
5-
import { globalOpenModal } from "@/ui/components/GlobalUIControls"
6-
import MatchResultsModal from "@/ui/modals/MatchResultsModal"
5+
import { globalOpenModal } from "@/components/GlobalUIControls.ts"
6+
import MatchResultsModal from "@/modals/MatchResultsModal.tsx"
7+
import DefaultMatchModeConfigs from "@/systems/match_mode/DefaultMatchModeConfigs.ts"
78
import type { MatchModeConfig } from "@/ui/panels/configuring/MatchModeConfigPanel"
89
import SimulationSystem from "../simulation/SimulationSystem"
910
import { SoundPlayer } from "../sound/SoundPlayer"
10-
import {
11-
DEFAULT_AUTONOMOUS_TIME,
12-
DEFAULT_TELEOP_TIME,
13-
DEFAULT_ENDGAME_TIME,
14-
DEFAULT_IGNORE_ROTATION,
15-
DEFAULT_MAX_HEIGHT,
16-
DEFAULT_HEIGHT_LIMIT_PENALTY,
17-
DEFAULT_SIDE_MAX_EXTENSION,
18-
DEFAULT_SIDE_EXTENSION_PENALTY,
19-
MatchModeType,
20-
} from "./MatchModeTypes"
11+
import { MatchModeType } from "./MatchModeTypes"
2112
import RobotDimensionTracker from "./RobotDimensionTracker"
2213

2314
class MatchMode {
@@ -35,19 +26,7 @@ class MatchMode {
3526
private _intervalId: number | null = null
3627

3728
// Match Mode Config
38-
private _matchModeConfig: MatchModeConfig = {
39-
id: "default",
40-
name: "Default",
41-
isDefault: true,
42-
autonomousTime: DEFAULT_AUTONOMOUS_TIME,
43-
teleopTime: DEFAULT_TELEOP_TIME,
44-
endgameTime: DEFAULT_ENDGAME_TIME,
45-
ignoreRotation: DEFAULT_IGNORE_ROTATION,
46-
maxHeight: DEFAULT_MAX_HEIGHT,
47-
heightLimitPenalty: DEFAULT_HEIGHT_LIMIT_PENALTY,
48-
sideExtensionPenalty: DEFAULT_SIDE_EXTENSION_PENALTY,
49-
sideMaxExtension: DEFAULT_SIDE_MAX_EXTENSION,
50-
}
29+
private _matchModeConfig: MatchModeConfig = DefaultMatchModeConfigs.fallbackValues()
5130

5231
private constructor() {}
5332

fission/src/systems/match_mode/MatchModeTypes.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,3 @@ export enum MatchModeType {
55
ENDGAME = "Endgame",
66
MATCH_ENDED = "Match Ended",
77
}
8-
9-
// Default match mode timing values
10-
export const DEFAULT_AUTONOMOUS_TIME = 15
11-
export const DEFAULT_TELEOP_TIME = 135
12-
export const DEFAULT_ENDGAME_TIME = 20
13-
export const DEFAULT_IGNORE_ROTATION = true
14-
export const DEFAULT_MAX_HEIGHT = Infinity
15-
export const DEFAULT_HEIGHT_LIMIT_PENALTY = 2
16-
export const DEFAULT_SIDE_MAX_EXTENSION = Infinity
17-
export const DEFAULT_SIDE_EXTENSION_PENALTY = 2

fission/src/systems/match_mode/RobotDimensionTracker.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import { MiraType } from "@/mirabuf/MirabufLoader"
2-
import MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
31
import SimulationSystem from "@/systems/simulation/SimulationSystem"
4-
import World from "@/systems/World"
5-
import type SceneRenderer from "../scene/SceneRenderer"
2+
import World from "@/systems/World.ts"
63
import MatchMode from "./MatchMode"
74

85
const BUFFER_HEIGHT = 0.1
@@ -31,14 +28,10 @@ class RobotDimensionTracker {
3128
this._sideExtensionPenalty = sideExtensionPenalty
3229
}
3330

34-
public static update(sceneRenderer: SceneRenderer): void {
31+
public static update(): void {
3532
if (!MatchMode.getInstance().isMatchEnabled()) return
3633

37-
const robots = [...sceneRenderer.sceneObjects.values()].filter(
38-
(obj): obj is MirabufSceneObject => obj instanceof MirabufSceneObject && obj.miraType === MiraType.ROBOT
39-
)
40-
41-
robots.forEach(robot => {
34+
World.sceneRenderer.mirabufSceneObjects.getRobots().forEach(robot => {
4235
const dimensions = this._ignoreRotation ? robot.getDimensionsWithoutRotation() : robot.getDimensions()
4336

4437
if (dimensions.height > this._maxHeight + BUFFER_HEIGHT) {
@@ -69,11 +62,7 @@ class RobotDimensionTracker {
6962
this._robotSize.clear()
7063
this._robotLastFramePenalty.clear()
7164

72-
const robots = [...World.sceneRenderer.sceneObjects.values()].filter(
73-
(obj): obj is MirabufSceneObject => obj instanceof MirabufSceneObject && obj.miraType === MiraType.ROBOT
74-
)
75-
76-
robots.forEach(robot => {
65+
World.sceneRenderer.mirabufSceneObjects.getRobots().forEach(robot => {
7766
this._robotSize.set(robot.id, robot.getDimensions())
7867
})
7968
}

0 commit comments

Comments
 (0)