Skip to content

Commit 1d30fd7

Browse files
authored
Merge branch 'dev' into zachr/1942/bootstrap-tests
2 parents 47ed9f6 + 278177e commit 1d30fd7

File tree

11 files changed

+1613
-44
lines changed

11 files changed

+1613
-44
lines changed

fission/src/mirabuf/MirabufLoader.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,15 @@ class MirabufCachingService {
115115
*
116116
* @param {string} fetchLocation Location of Mirabuf file.
117117
* @param {MiraType} miraType Type of Mirabuf Assembly.
118+
* @param {string} name Optional display name for the cached file.
118119
*
119120
* @returns {Promise<MirabufCacheInfo | undefined>} Promise with the result of the promise. Metadata on the mirabuf file if successful, undefined if not.
120121
*/
121-
public static async cacheRemote(fetchLocation: string, miraType?: MiraType): Promise<MirabufCacheInfo | undefined> {
122+
public static async cacheRemote(
123+
fetchLocation: string,
124+
miraType?: MiraType,
125+
name?: string
126+
): Promise<MirabufCacheInfo | undefined> {
122127
if (miraType !== undefined) {
123128
const map = MirabufCachingService.getCacheMap(miraType)
124129
const target = map[fetchLocation]
@@ -136,7 +141,7 @@ class MirabufCachingService {
136141
fileSize: miraBuff.byteLength,
137142
})
138143

139-
const cached = await MirabufCachingService.storeInCache(fetchLocation, miraBuff, miraType)
144+
const cached = await MirabufCachingService.storeInCache(fetchLocation, miraBuff, miraType, name)
140145

141146
if (cached) return cached
142147

@@ -148,6 +153,7 @@ class MirabufCachingService {
148153
miraType: miraType ?? (this.assemblyFromBuffer(miraBuff).dynamic ? MiraType.ROBOT : MiraType.FIELD),
149154
cacheKey: fetchLocation,
150155
buffer: miraBuff,
156+
name: name,
151157
}
152158
} catch (e) {
153159
console.warn("Caching failed", e)

fission/src/systems/scene/CameraControls.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,6 @@ export class CustomOrbitControls extends CameraControls {
203203
return { ...this._coords }
204204
}
205205

206-
public setTargetCoordinates(coords: Partial<SphericalCoords>) {
207-
if (coords.theta !== undefined) this._nextCoords.theta = coords.theta
208-
if (coords.phi !== undefined) this._nextCoords.phi = coords.phi
209-
if (coords.r !== undefined) this._nextCoords.r = coords.r
210-
}
211-
212206
public setImmediateCoordinates(coords: Partial<SphericalCoords>) {
213207
if (coords.theta !== undefined) {
214208
this._coords.theta = coords.theta

fission/src/systems/scene/DragModeSystem.ts

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ import * as THREE from "three"
22
import WorldSystem from "../WorldSystem"
33
import World from "../World"
44
import JOLT from "@/util/loading/JoltSyncLoader"
5-
import { convertThreeVector3ToJoltVec3, convertJoltVec3ToThreeVector3 } from "@/util/TypeConversions"
5+
import { convertJoltVec3ToThreeVector3, convertThreeVector3ToJoltVec3 } from "@/util/TypeConversions"
66
import MirabufSceneObject, { RigidNodeAssociate } from "@/mirabuf/MirabufSceneObject"
77
import {
8-
InteractionStart,
9-
InteractionMove,
108
InteractionEnd,
9+
InteractionMove,
10+
InteractionStart,
1111
PRIMARY_MOUSE_INTERACTION,
1212
} from "./ScreenInteractionHandler"
1313
import { CustomOrbitControls, SphericalCoords } from "./CameraControls"
1414
import Jolt from "@azaleacolburn/jolt-physics"
1515
import { MiraType } from "@/mirabuf/MirabufLoader"
16+
import InputSystem from "@/systems/input/InputSystem.ts"
1617

1718
interface DragTarget {
1819
bodyId: Jolt.BodyID
@@ -59,6 +60,7 @@ class DragModeSystem extends WorldSystem {
5960
// Precision and sensitivity
6061
MINIMUM_DISTANCE_THRESHOLD: 0.02, // Minimum distance to apply forces (smaller = more precision)
6162
WHEEL_SCROLL_SENSITIVITY: -0.01, // Mouse wheel scroll sensitivity for Z-axis
63+
ROTATION_SPEED: 200.0, // speed of arrow key rotation. lower = more precise, higher = more
6264
} as const
6365

6466
private _enabled: boolean = false
@@ -564,25 +566,19 @@ class DragModeSystem extends WorldSystem {
564566
const joltForce = convertThreeVector3ToJoltVec3(forceNeeded)
565567
body.AddForce(joltForce)
566568

567-
// Calculate torque to simulate force applied at the drag point
568-
// Use the current world offset (which rotates with the body)
569-
const leverArm = currentWorldOffset // vector from COM to drag point in world coordinates
570-
const torque = leverArm.cross(forceNeeded) // Cross product gives us the torque
571-
const joltTorque = convertThreeVector3ToJoltVec3(torque)
572-
body.AddTorque(joltTorque)
573-
574-
// Reduce angular damping since we want the natural rotation from the applied force
575-
const angularVel = body.GetAngularVelocity()
576-
const angularDampingStrength = Math.min(
577-
mass * DragModeSystem.DRAG_FORCE_CONSTANTS.ANGULAR_DAMPING_BASE,
578-
DragModeSystem.DRAG_FORCE_CONSTANTS.ANGULAR_DAMPING_MAX
569+
const yawRotation = new JOLT.Vec3(
570+
0,
571+
DragModeSystem.DRAG_FORCE_CONSTANTS.ROTATION_SPEED *
572+
(InputSystem.isKeyPressed("ArrowRight") ? 1 : 0 - (InputSystem.isKeyPressed("ArrowLeft") ? 1 : 0)),
573+
0
579574
)
580-
const angularDampingTorque = new JOLT.Vec3(
581-
-angularVel.GetX() * angularDampingStrength,
582-
-angularVel.GetY() * angularDampingStrength,
583-
-angularVel.GetZ() * angularDampingStrength
575+
const cameraVector = World.sceneRenderer.mainCamera.getWorldDirection(new THREE.Vector3(0, 0, 0))
576+
const pitchRotation = new JOLT.Vec3(cameraVector.z, 0, -cameraVector.x).Mul(
577+
DragModeSystem.DRAG_FORCE_CONSTANTS.ROTATION_SPEED *
578+
(InputSystem.isKeyPressed("ArrowUp") ? 1 : 0 - (InputSystem.isKeyPressed("ArrowDown") ? 1 : 0))
584579
)
585-
body.AddTorque(angularDampingTorque)
580+
body.AddTorque(yawRotation)
581+
body.AddTorque(pitchRotation)
586582
} else {
587583
// When close to target, apply braking forces and gravity compensation
588584
const currentVel = body.GetLinearVelocity()
@@ -602,21 +598,9 @@ class DragModeSystem extends WorldSystem {
602598
const gravityCompensationY = mass * DragModeSystem.DRAG_FORCE_CONSTANTS.GRAVITY_MAGNITUDE
603599
brakingForce.SetY(brakingForce.GetY() + gravityCompensationY)
604600
}
605-
606601
body.AddForce(brakingForce)
607-
608-
const angularVel = body.GetAngularVelocity()
609-
const angularBrakingStrength = Math.min(
610-
mass * DragModeSystem.DRAG_FORCE_CONSTANTS.ANGULAR_BRAKING_BASE,
611-
DragModeSystem.DRAG_FORCE_CONSTANTS.ANGULAR_BRAKING_MAX
612-
)
613-
const angularBrakingTorque = new JOLT.Vec3(
614-
-angularVel.GetX() * angularBrakingStrength,
615-
-angularVel.GetY() * angularBrakingStrength,
616-
-angularVel.GetZ() * angularBrakingStrength
617-
)
618-
body.AddTorque(angularBrakingTorque)
619602
}
603+
body.SetAngularVelocity(new JOLT.Vec3())
620604
}
621605

622606
private handleWheelDuringDrag(event: WheelEvent): void {

fission/src/systems/scene/SceneRenderer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ const CLEAR_COLOR = 0x121212
2727
const GROUND_COLOR = 0xfffef0
2828

2929
const STANDARD_ASPECT = 16.0 / 9.0
30-
const STANDARD_CAMERA_FOV_X = 110.0
31-
const STANDARD_CAMERA_FOV_Y = STANDARD_CAMERA_FOV_X / STANDARD_ASPECT
30+
export const STANDARD_CAMERA_FOV_X = 110.0
31+
export const STANDARD_CAMERA_FOV_Y = STANDARD_CAMERA_FOV_X / STANDARD_ASPECT
3232

3333
const textureLoader = new THREE.TextureLoader()
3434

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { expect, test, beforeEach, describe } from "vitest"
2+
import { CustomOrbitControls } from "@/systems/scene/CameraControls"
3+
import * as THREE from "three"
4+
import ScreenInteractionHandler, { InteractionType } from "@/systems/scene/ScreenInteractionHandler"
5+
6+
describe("CustomOrbitControls", () => {
7+
let camera: THREE.PerspectiveCamera
8+
let interactionHandler: ScreenInteractionHandler
9+
let controls: CustomOrbitControls
10+
11+
beforeEach(() => {
12+
camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000)
13+
camera.position.set(0, 0, 5)
14+
15+
const mockElement = document.createElement("div")
16+
interactionHandler = new ScreenInteractionHandler(mockElement)
17+
18+
controls = new CustomOrbitControls(camera, interactionHandler)
19+
})
20+
21+
describe("Camera Position and Update", () => {
22+
test("sets simple coordinates correctly", () => {
23+
controls.setImmediateCoordinates({ theta: Math.PI / 2, phi: 0, r: 2.0 })
24+
controls.update(1 / 60)
25+
26+
expect(camera.position.x).toBeCloseTo(2)
27+
expect(camera.position.y).toBeCloseTo(0)
28+
expect(camera.position.z).toBeCloseTo(0)
29+
})
30+
31+
test("sets complex coordinates correctly", () => {
32+
controls.setImmediateCoordinates({ theta: Math.PI / 3, phi: Math.PI / 6, r: 4.0 })
33+
controls.update(1 / 60)
34+
35+
expect(camera.position.distanceTo(new THREE.Vector3(0, 0, 0))).toBeCloseTo(4)
36+
37+
expect(camera.position.x).toBeCloseTo(3)
38+
expect(camera.position.y).toBeCloseTo(-2)
39+
expect(camera.position.z).toBeCloseTo(1.732)
40+
})
41+
42+
test("clamps extreme values", () => {
43+
// Test r (zoom) bounds - values should be clamped
44+
controls.setImmediateCoordinates({ r: 1000 })
45+
controls.update(1 / 60)
46+
const maxR = controls.getCurrentCoordinates().r
47+
48+
controls.setImmediateCoordinates({ r: 0.001 })
49+
controls.update(1 / 60)
50+
const minR = controls.getCurrentCoordinates().r
51+
52+
expect(maxR).toBeLessThan(1000)
53+
expect(minR).toBeGreaterThan(0.001)
54+
expect(minR).toBeLessThan(maxR)
55+
56+
// Test phi (vertical) bounds
57+
controls.setImmediateCoordinates({ phi: Math.PI })
58+
controls.update(1 / 60)
59+
const maxPhi = controls.getCurrentCoordinates().phi
60+
61+
controls.setImmediateCoordinates({ phi: -Math.PI })
62+
controls.update(1 / 60)
63+
const minPhi = controls.getCurrentCoordinates().phi
64+
65+
expect(maxPhi).toBeLessThan(Math.PI)
66+
expect(minPhi).toBeGreaterThan(-Math.PI)
67+
expect(minPhi).toBeLessThan(maxPhi)
68+
})
69+
})
70+
71+
describe("Mouse Interaction", () => {
72+
const simulateMouseInteraction = (options: {
73+
startPosition: [number, number]
74+
movement?: [number, number]
75+
scale?: number
76+
updateFrames: number
77+
endPosition: [number, number]
78+
interactionType?: InteractionType
79+
}) => {
80+
const { startPosition, movement, scale, updateFrames, endPosition, interactionType = 0 } = options
81+
82+
controls.interactionStart({
83+
interactionType,
84+
position: startPosition,
85+
})
86+
87+
if (movement || scale !== undefined) {
88+
controls.interactionMove({
89+
interactionType,
90+
movement,
91+
scale,
92+
})
93+
}
94+
95+
for (let i = 0; i < updateFrames; i++) {
96+
controls.update(1 / 60)
97+
}
98+
99+
controls.interactionEnd({
100+
interactionType,
101+
position: endPosition,
102+
})
103+
104+
for (let i = 0; i < 10; i++) {
105+
controls.update(1 / 60)
106+
}
107+
}
108+
109+
beforeEach(() => {
110+
controls.setImmediateCoordinates({ theta: 0, phi: 0, r: 5 })
111+
controls.update(1 / 60)
112+
})
113+
114+
test("simulate mouse drag", () => {
115+
const initialCoords = controls.getCurrentCoordinates()
116+
117+
simulateMouseInteraction({
118+
startPosition: [100, 100],
119+
movement: [0.28, -0.105],
120+
updateFrames: 60,
121+
endPosition: [180, 70],
122+
})
123+
124+
expect(controls.getCurrentCoordinates()).not.toEqual(initialCoords)
125+
126+
expect(camera.position.distanceTo(new THREE.Vector3(0, 0, 0))).toBeCloseTo(5)
127+
})
128+
129+
test("should zoom in and out correctly", () => {
130+
const initialDistance = camera.position.distanceTo(new THREE.Vector3(0, 0, 0))
131+
expect(initialDistance).toBeCloseTo(5, 0)
132+
133+
simulateMouseInteraction({
134+
scale: -1.0,
135+
updateFrames: 1,
136+
startPosition: [100, 100],
137+
endPosition: [100, 100],
138+
})
139+
140+
const zoomedInDistance = camera.position.distanceTo(new THREE.Vector3(0, 0, 0))
141+
142+
simulateMouseInteraction({
143+
scale: 2.0,
144+
updateFrames: 1,
145+
startPosition: [100, 100],
146+
endPosition: [100, 100],
147+
})
148+
149+
const finalDistance = camera.position.distanceTo(new THREE.Vector3(0, 0, 0))
150+
151+
expect(zoomedInDistance).toBeCloseTo(4, 0)
152+
expect(finalDistance).toBeCloseTo(5.4, 0)
153+
})
154+
155+
test("should not update when disabled", () => {
156+
const initialPosition = camera.position.clone()
157+
158+
controls.enabled = false
159+
160+
simulateMouseInteraction({
161+
startPosition: [100, 100],
162+
movement: [0.175, 0.35],
163+
updateFrames: 30,
164+
endPosition: [150, 200],
165+
})
166+
167+
expect(camera.position.distanceTo(initialPosition)).toBeCloseTo(0)
168+
})
169+
})
170+
})

0 commit comments

Comments
 (0)