@guinetik/gcanvas 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gcanvas.es.js +25656 -0
- package/dist/gcanvas.es.min.js +1 -0
- package/dist/gcanvas.umd.js +1 -0
- package/dist/gcanvas.umd.min.js +1 -0
- package/package.json +23 -6
- package/src/game/objects/index.js +1 -0
- package/src/game/objects/spritesheet.js +260 -0
- package/src/game/ui/theme.js +6 -0
- package/src/io/keys.js +9 -1
- package/src/math/boolean.js +481 -0
- package/src/math/index.js +1 -0
- package/.github/workflows/release.yaml +0 -70
- package/.jshintrc +0 -4
- package/.vscode/settings.json +0 -22
- package/CLAUDE.md +0 -310
- package/blackhole.jpg +0 -0
- package/demo.png +0 -0
- package/demos/CNAME +0 -1
- package/demos/animations.html +0 -31
- package/demos/basic.html +0 -38
- package/demos/baskara.html +0 -31
- package/demos/bezier.html +0 -35
- package/demos/beziersignature.html +0 -29
- package/demos/blackhole.html +0 -28
- package/demos/blob.html +0 -35
- package/demos/coordinates.html +0 -698
- package/demos/cube3d.html +0 -23
- package/demos/demos.css +0 -303
- package/demos/dino.html +0 -42
- package/demos/easing.html +0 -28
- package/demos/events.html +0 -195
- package/demos/fluent.html +0 -647
- package/demos/fluid-simple.html +0 -22
- package/demos/fluid.html +0 -37
- package/demos/fractals.html +0 -36
- package/demos/gameobjects.html +0 -626
- package/demos/genart.html +0 -26
- package/demos/gendream.html +0 -26
- package/demos/group.html +0 -36
- package/demos/home.html +0 -587
- package/demos/index.html +0 -376
- package/demos/isometric.html +0 -34
- package/demos/js/animations.js +0 -452
- package/demos/js/basic.js +0 -204
- package/demos/js/baskara.js +0 -751
- package/demos/js/bezier.js +0 -692
- package/demos/js/beziersignature.js +0 -241
- package/demos/js/blackhole/accretiondisk.obj.js +0 -379
- package/demos/js/blackhole/blackhole.obj.js +0 -318
- package/demos/js/blackhole/index.js +0 -409
- package/demos/js/blackhole/particle.js +0 -56
- package/demos/js/blackhole/starfield.obj.js +0 -218
- package/demos/js/blob.js +0 -2276
- package/demos/js/coordinates.js +0 -840
- package/demos/js/cube3d.js +0 -789
- package/demos/js/dino.js +0 -1420
- package/demos/js/easing.js +0 -477
- package/demos/js/fluent.js +0 -183
- package/demos/js/fluid-simple.js +0 -253
- package/demos/js/fluid.js +0 -527
- package/demos/js/fractals.js +0 -931
- package/demos/js/fractalworker.js +0 -93
- package/demos/js/gameobjects.js +0 -176
- package/demos/js/genart.js +0 -268
- package/demos/js/gendream.js +0 -209
- package/demos/js/group.js +0 -140
- package/demos/js/info-toggle.js +0 -25
- package/demos/js/isometric.js +0 -863
- package/demos/js/kerr.js +0 -1556
- package/demos/js/lavalamp.js +0 -590
- package/demos/js/layout.js +0 -354
- package/demos/js/mondrian.js +0 -285
- package/demos/js/opacity.js +0 -275
- package/demos/js/painter.js +0 -484
- package/demos/js/particles-showcase.js +0 -514
- package/demos/js/particles.js +0 -299
- package/demos/js/patterns.js +0 -397
- package/demos/js/penrose/artifact.js +0 -69
- package/demos/js/penrose/blackhole.js +0 -121
- package/demos/js/penrose/constants.js +0 -73
- package/demos/js/penrose/game.js +0 -943
- package/demos/js/penrose/lore.js +0 -278
- package/demos/js/penrose/penrosescene.js +0 -892
- package/demos/js/penrose/ship.js +0 -216
- package/demos/js/penrose/sounds.js +0 -211
- package/demos/js/penrose/voidparticle.js +0 -55
- package/demos/js/penrose/voidscene.js +0 -258
- package/demos/js/penrose/voidship.js +0 -144
- package/demos/js/penrose/wormhole.js +0 -46
- package/demos/js/pipeline.js +0 -555
- package/demos/js/plane3d.js +0 -256
- package/demos/js/platformer.js +0 -1579
- package/demos/js/scene.js +0 -304
- package/demos/js/scenes.js +0 -320
- package/demos/js/schrodinger.js +0 -410
- package/demos/js/schwarzschild.js +0 -1023
- package/demos/js/shapes.js +0 -628
- package/demos/js/space/alien.js +0 -171
- package/demos/js/space/boom.js +0 -98
- package/demos/js/space/boss.js +0 -353
- package/demos/js/space/buff.js +0 -73
- package/demos/js/space/bullet.js +0 -102
- package/demos/js/space/constants.js +0 -85
- package/demos/js/space/game.js +0 -1884
- package/demos/js/space/hud.js +0 -112
- package/demos/js/space/laserbeam.js +0 -179
- package/demos/js/space/lightning.js +0 -277
- package/demos/js/space/minion.js +0 -192
- package/demos/js/space/missile.js +0 -212
- package/demos/js/space/player.js +0 -430
- package/demos/js/space/powerup.js +0 -90
- package/demos/js/space/starfield.js +0 -58
- package/demos/js/space/starpower.js +0 -90
- package/demos/js/spacetime.js +0 -559
- package/demos/js/sphere3d.js +0 -229
- package/demos/js/sprite.js +0 -473
- package/demos/js/svgtween.js +0 -204
- package/demos/js/tde/accretiondisk.js +0 -471
- package/demos/js/tde/blackhole.js +0 -219
- package/demos/js/tde/blackholescene.js +0 -209
- package/demos/js/tde/config.js +0 -59
- package/demos/js/tde/index.js +0 -820
- package/demos/js/tde/jets.js +0 -290
- package/demos/js/tde/lensedstarfield.js +0 -154
- package/demos/js/tde/tdestar.js +0 -297
- package/demos/js/tde/tidalstream.js +0 -372
- package/demos/js/tde_old/blackhole.obj.js +0 -354
- package/demos/js/tde_old/debris.obj.js +0 -791
- package/demos/js/tde_old/flare.obj.js +0 -239
- package/demos/js/tde_old/index.js +0 -448
- package/demos/js/tde_old/star.obj.js +0 -812
- package/demos/js/tiles.js +0 -312
- package/demos/js/tweendemo.js +0 -79
- package/demos/js/visibility.js +0 -102
- package/demos/kerr.html +0 -28
- package/demos/lavalamp.html +0 -27
- package/demos/layouts.html +0 -37
- package/demos/logo.svg +0 -4
- package/demos/loop.html +0 -84
- package/demos/mondrian.html +0 -32
- package/demos/og_image.png +0 -0
- package/demos/opacity.html +0 -36
- package/demos/painter.html +0 -39
- package/demos/particles-showcase.html +0 -28
- package/demos/particles.html +0 -24
- package/demos/patterns.html +0 -33
- package/demos/penrose-game.html +0 -31
- package/demos/pipeline.html +0 -737
- package/demos/plane3d.html +0 -24
- package/demos/platformer.html +0 -43
- package/demos/scene.html +0 -33
- package/demos/scenes.html +0 -96
- package/demos/schrodinger.html +0 -27
- package/demos/schwarzschild.html +0 -27
- package/demos/shapes.html +0 -16
- package/demos/space.html +0 -85
- package/demos/spacetime.html +0 -27
- package/demos/sphere3d.html +0 -24
- package/demos/sprite.html +0 -18
- package/demos/svgtween.html +0 -29
- package/demos/tde.html +0 -28
- package/demos/tiles.html +0 -28
- package/demos/transforms.html +0 -400
- package/demos/tween.html +0 -45
- package/demos/visibility.html +0 -33
- package/docs/README.md +0 -230
- package/docs/api/FluidSystem.md +0 -173
- package/docs/concepts/architecture-overview.md +0 -204
- package/docs/concepts/coordinate-system.md +0 -384
- package/docs/concepts/lifecycle.md +0 -255
- package/docs/concepts/rendering-pipeline.md +0 -279
- package/docs/concepts/shapes-vs-gameobjects.md +0 -187
- package/docs/concepts/tde-zorder.md +0 -106
- package/docs/concepts/two-layer-architecture.md +0 -229
- package/docs/fluid-dynamics.md +0 -99
- package/docs/getting-started/first-game.md +0 -354
- package/docs/getting-started/hello-world.md +0 -269
- package/docs/getting-started/installation.md +0 -175
- package/docs/modules/collision/README.md +0 -453
- package/docs/modules/fluent/README.md +0 -1075
- package/docs/modules/game/README.md +0 -303
- package/docs/modules/isometric-camera.md +0 -210
- package/docs/modules/isometric.md +0 -275
- package/docs/modules/painter/README.md +0 -328
- package/docs/modules/particle/README.md +0 -559
- package/docs/modules/shapes/README.md +0 -221
- package/docs/modules/shapes/base/euclidian.md +0 -123
- package/docs/modules/shapes/base/geometry2d.md +0 -204
- package/docs/modules/shapes/base/renderable.md +0 -215
- package/docs/modules/shapes/base/shape.md +0 -262
- package/docs/modules/shapes/base/transformable.md +0 -243
- package/docs/modules/shapes/hierarchy.md +0 -218
- package/docs/modules/state/README.md +0 -577
- package/docs/modules/util/README.md +0 -99
- package/docs/modules/util/camera3d.md +0 -412
- package/docs/modules/util/scene3d.md +0 -395
- package/index.html +0 -17
- package/jsdoc.json +0 -50
- package/scripts/build-demo.js +0 -69
- package/scripts/bundle4llm.js +0 -276
- package/scripts/clearconsole.js +0 -48
- package/test/math/orbital.test.js +0 -61
- package/test/math/tensor.test.js +0 -114
- package/test/particle/emitter.test.js +0 -204
- package/test/particle/particle-system.test.js +0 -310
- package/test/particle/particle.test.js +0 -116
- package/test/particle/updaters.test.js +0 -386
- package/test/setup.js +0 -120
- package/test/shapes/euclidian.test.js +0 -44
- package/test/shapes/geometry.test.js +0 -86
- package/test/shapes/group.test.js +0 -86
- package/test/shapes/rectangle.test.js +0 -64
- package/test/shapes/transform.test.js +0 -379
- package/test/util/camera3d.test.js +0 -428
- package/test/util/scene3d.test.js +0 -352
- package/vite.config.js +0 -50
- package/vitest.config.js +0 -13
|
@@ -1,428 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { Camera3D } from "../../src/util/camera3d";
|
|
3
|
-
|
|
4
|
-
describe("Camera3D", () => {
|
|
5
|
-
describe("constructor", () => {
|
|
6
|
-
it("should initialize with default values", () => {
|
|
7
|
-
const camera = new Camera3D();
|
|
8
|
-
|
|
9
|
-
expect(camera.rotationX).toBe(0);
|
|
10
|
-
expect(camera.rotationY).toBe(0);
|
|
11
|
-
expect(camera.rotationZ).toBe(0);
|
|
12
|
-
expect(camera.perspective).toBe(800);
|
|
13
|
-
expect(camera.sensitivity).toBe(0.005);
|
|
14
|
-
expect(camera.minRotationX).toBe(-1.5);
|
|
15
|
-
expect(camera.maxRotationX).toBe(1.5);
|
|
16
|
-
expect(camera.clampX).toBe(true);
|
|
17
|
-
expect(camera.autoRotate).toBe(false);
|
|
18
|
-
expect(camera.autoRotateSpeed).toBe(0.5);
|
|
19
|
-
expect(camera.autoRotateAxis).toBe("y");
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("should accept custom options", () => {
|
|
23
|
-
const camera = new Camera3D({
|
|
24
|
-
rotationX: 0.5,
|
|
25
|
-
rotationY: -0.3,
|
|
26
|
-
rotationZ: 0.1,
|
|
27
|
-
perspective: 1200,
|
|
28
|
-
sensitivity: 0.01,
|
|
29
|
-
minRotationX: -1.0,
|
|
30
|
-
maxRotationX: 1.0,
|
|
31
|
-
clampX: false,
|
|
32
|
-
autoRotate: true,
|
|
33
|
-
autoRotateSpeed: 1.0,
|
|
34
|
-
autoRotateAxis: "x",
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(camera.rotationX).toBe(0.5);
|
|
38
|
-
expect(camera.rotationY).toBe(-0.3);
|
|
39
|
-
expect(camera.rotationZ).toBe(0.1);
|
|
40
|
-
expect(camera.perspective).toBe(1200);
|
|
41
|
-
expect(camera.sensitivity).toBe(0.01);
|
|
42
|
-
expect(camera.minRotationX).toBe(-1.0);
|
|
43
|
-
expect(camera.maxRotationX).toBe(1.0);
|
|
44
|
-
expect(camera.clampX).toBe(false);
|
|
45
|
-
expect(camera.autoRotate).toBe(true);
|
|
46
|
-
expect(camera.autoRotateSpeed).toBe(1.0);
|
|
47
|
-
expect(camera.autoRotateAxis).toBe("x");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("should store initial rotation for reset", () => {
|
|
51
|
-
const camera = new Camera3D({
|
|
52
|
-
rotationX: 0.5,
|
|
53
|
-
rotationY: 0.3,
|
|
54
|
-
rotationZ: 0.1,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
expect(camera._initialRotationX).toBe(0.5);
|
|
58
|
-
expect(camera._initialRotationY).toBe(0.3);
|
|
59
|
-
expect(camera._initialRotationZ).toBe(0.1);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("project", () => {
|
|
64
|
-
it("should project origin to origin with no rotation", () => {
|
|
65
|
-
const camera = new Camera3D();
|
|
66
|
-
const result = camera.project(0, 0, 0);
|
|
67
|
-
|
|
68
|
-
expect(result.x).toBe(0);
|
|
69
|
-
expect(result.y).toBe(0);
|
|
70
|
-
expect(result.z).toBe(0);
|
|
71
|
-
expect(result.scale).toBe(1);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("should apply perspective scaling", () => {
|
|
75
|
-
const camera = new Camera3D({ perspective: 800 });
|
|
76
|
-
|
|
77
|
-
// Point at z=400 (halfway to perspective)
|
|
78
|
-
const result = camera.project(0, 0, 400);
|
|
79
|
-
|
|
80
|
-
// scale = 800 / (800 + 400) = 800 / 1200 = 0.667
|
|
81
|
-
expect(result.scale).toBeCloseTo(0.667, 2);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("should project point closer when z is negative", () => {
|
|
85
|
-
const camera = new Camera3D({ perspective: 800 });
|
|
86
|
-
|
|
87
|
-
// Point at z=-400 (in front)
|
|
88
|
-
const result = camera.project(100, 0, -400);
|
|
89
|
-
|
|
90
|
-
// scale = 800 / (800 - 400) = 800 / 400 = 2
|
|
91
|
-
expect(result.scale).toBe(2);
|
|
92
|
-
expect(result.x).toBe(200); // 100 * 2
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("should apply Y rotation", () => {
|
|
96
|
-
const camera = new Camera3D({
|
|
97
|
-
rotationY: Math.PI / 2, // 90 degrees
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Point at x=100 should now be at z after rotation
|
|
101
|
-
const result = camera.project(100, 0, 0);
|
|
102
|
-
|
|
103
|
-
// After 90 degree Y rotation: x1 = x*cos - z*sin = 100*0 - 0*1 = 0
|
|
104
|
-
// z1 = x*sin + z*cos = 100*1 + 0*0 = 100
|
|
105
|
-
expect(result.x).toBeCloseTo(0, 5);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("should apply X rotation", () => {
|
|
109
|
-
const camera = new Camera3D({
|
|
110
|
-
rotationX: Math.PI / 2, // 90 degrees
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Point at y=100 should rotate to z
|
|
114
|
-
const result = camera.project(0, 100, 0);
|
|
115
|
-
|
|
116
|
-
// After 90 degree X rotation: y1 = y*cos - z*sin = 100*0 - 0*1 = 0
|
|
117
|
-
expect(result.y).toBeCloseTo(0, 5);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should apply Z rotation (roll)", () => {
|
|
121
|
-
const camera = new Camera3D({
|
|
122
|
-
rotationZ: Math.PI / 2, // 90 degrees
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// Point at x=100 should rotate to y
|
|
126
|
-
const result = camera.project(100, 0, 0);
|
|
127
|
-
|
|
128
|
-
// After 90 degree Z rotation: x = x*cos - y*sin = 100*0 - 0*1 = 0
|
|
129
|
-
// y = x*sin + y*cos = 100*1 + 0*0 = 100
|
|
130
|
-
expect(result.x).toBeCloseTo(0, 5);
|
|
131
|
-
expect(result.y).toBeCloseTo(100, 5);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("should return depth for sorting", () => {
|
|
135
|
-
const camera = new Camera3D();
|
|
136
|
-
|
|
137
|
-
const front = camera.project(0, 0, -100);
|
|
138
|
-
const back = camera.project(0, 0, 100);
|
|
139
|
-
|
|
140
|
-
expect(front.z).toBeLessThan(back.z);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe("projectAll", () => {
|
|
145
|
-
it("should project multiple points", () => {
|
|
146
|
-
const camera = new Camera3D();
|
|
147
|
-
const points = [
|
|
148
|
-
{ x: 100, y: 0, z: 0 },
|
|
149
|
-
{ x: 0, y: 100, z: 0 },
|
|
150
|
-
{ x: 0, y: 0, z: 100 },
|
|
151
|
-
];
|
|
152
|
-
|
|
153
|
-
const results = camera.projectAll(points);
|
|
154
|
-
|
|
155
|
-
expect(results.length).toBe(3);
|
|
156
|
-
expect(results[0]).toHaveProperty("x");
|
|
157
|
-
expect(results[0]).toHaveProperty("y");
|
|
158
|
-
expect(results[0]).toHaveProperty("z");
|
|
159
|
-
expect(results[0]).toHaveProperty("scale");
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe("update", () => {
|
|
164
|
-
it("should auto-rotate when enabled", () => {
|
|
165
|
-
const camera = new Camera3D({
|
|
166
|
-
autoRotate: true,
|
|
167
|
-
autoRotateSpeed: 1.0,
|
|
168
|
-
autoRotateAxis: "y",
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
camera.update(0.5);
|
|
172
|
-
|
|
173
|
-
expect(camera.rotationY).toBe(0.5);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("should auto-rotate on different axes", () => {
|
|
177
|
-
const cameraX = new Camera3D({
|
|
178
|
-
autoRotate: true,
|
|
179
|
-
autoRotateSpeed: 1.0,
|
|
180
|
-
autoRotateAxis: "x",
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const cameraZ = new Camera3D({
|
|
184
|
-
autoRotate: true,
|
|
185
|
-
autoRotateSpeed: 1.0,
|
|
186
|
-
autoRotateAxis: "z",
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
cameraX.update(1);
|
|
190
|
-
cameraZ.update(1);
|
|
191
|
-
|
|
192
|
-
expect(cameraX.rotationX).toBe(1);
|
|
193
|
-
expect(cameraZ.rotationZ).toBe(1);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it("should not auto-rotate when disabled", () => {
|
|
197
|
-
const camera = new Camera3D({
|
|
198
|
-
autoRotate: false,
|
|
199
|
-
autoRotateSpeed: 1.0,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
camera.update(1);
|
|
203
|
-
|
|
204
|
-
expect(camera.rotationY).toBe(0);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it("should not auto-rotate while dragging", () => {
|
|
208
|
-
const camera = new Camera3D({
|
|
209
|
-
autoRotate: true,
|
|
210
|
-
autoRotateSpeed: 1.0,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
camera._isDragging = true;
|
|
214
|
-
camera.update(1);
|
|
215
|
-
|
|
216
|
-
expect(camera.rotationY).toBe(0);
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
describe("setRotation", () => {
|
|
221
|
-
it("should set rotation values", () => {
|
|
222
|
-
const camera = new Camera3D();
|
|
223
|
-
|
|
224
|
-
camera.setRotation(0.5, 0.3, 0.1);
|
|
225
|
-
|
|
226
|
-
expect(camera.rotationX).toBe(0.5);
|
|
227
|
-
expect(camera.rotationY).toBe(0.3);
|
|
228
|
-
expect(camera.rotationZ).toBe(0.1);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("should default z to 0", () => {
|
|
232
|
-
const camera = new Camera3D({ rotationZ: 1 });
|
|
233
|
-
|
|
234
|
-
camera.setRotation(0.5, 0.3);
|
|
235
|
-
|
|
236
|
-
expect(camera.rotationZ).toBe(0);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("should return this for chaining", () => {
|
|
240
|
-
const camera = new Camera3D();
|
|
241
|
-
const result = camera.setRotation(0.5, 0.3);
|
|
242
|
-
|
|
243
|
-
expect(result).toBe(camera);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
describe("rotate", () => {
|
|
248
|
-
it("should add to current rotation", () => {
|
|
249
|
-
const camera = new Camera3D({
|
|
250
|
-
rotationX: 0.1,
|
|
251
|
-
rotationY: 0.2,
|
|
252
|
-
rotationZ: 0.3,
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
camera.rotate(0.1, 0.1, 0.1);
|
|
256
|
-
|
|
257
|
-
expect(camera.rotationX).toBeCloseTo(0.2);
|
|
258
|
-
expect(camera.rotationY).toBeCloseTo(0.3);
|
|
259
|
-
expect(camera.rotationZ).toBeCloseTo(0.4);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("should clamp X rotation when enabled", () => {
|
|
263
|
-
const camera = new Camera3D({
|
|
264
|
-
clampX: true,
|
|
265
|
-
minRotationX: -1.0,
|
|
266
|
-
maxRotationX: 1.0,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
camera.rotate(2.0, 0, 0);
|
|
270
|
-
|
|
271
|
-
expect(camera.rotationX).toBe(1.0);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it("should not clamp X when disabled", () => {
|
|
275
|
-
const camera = new Camera3D({
|
|
276
|
-
clampX: false,
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
camera.rotate(3.0, 0, 0);
|
|
280
|
-
|
|
281
|
-
expect(camera.rotationX).toBe(3.0);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("should return this for chaining", () => {
|
|
285
|
-
const camera = new Camera3D();
|
|
286
|
-
const result = camera.rotate(0.1, 0.1);
|
|
287
|
-
|
|
288
|
-
expect(result).toBe(camera);
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
describe("reset", () => {
|
|
293
|
-
it("should reset to initial rotation", () => {
|
|
294
|
-
const camera = new Camera3D({
|
|
295
|
-
rotationX: 0.5,
|
|
296
|
-
rotationY: 0.3,
|
|
297
|
-
rotationZ: 0.1,
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
camera.rotationX = 1.0;
|
|
301
|
-
camera.rotationY = 1.0;
|
|
302
|
-
camera.rotationZ = 1.0;
|
|
303
|
-
|
|
304
|
-
camera.reset();
|
|
305
|
-
|
|
306
|
-
expect(camera.rotationX).toBe(0.5);
|
|
307
|
-
expect(camera.rotationY).toBe(0.3);
|
|
308
|
-
expect(camera.rotationZ).toBe(0.1);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
it("should return this for chaining", () => {
|
|
312
|
-
const camera = new Camera3D();
|
|
313
|
-
const result = camera.reset();
|
|
314
|
-
|
|
315
|
-
expect(result).toBe(camera);
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
describe("lookAt", () => {
|
|
320
|
-
it("should set rotation to face a point", () => {
|
|
321
|
-
const camera = new Camera3D();
|
|
322
|
-
|
|
323
|
-
camera.lookAt(0, 0, 100);
|
|
324
|
-
|
|
325
|
-
// Looking straight ahead (positive Z)
|
|
326
|
-
expect(camera.rotationY).toBeCloseTo(0, 5);
|
|
327
|
-
expect(camera.rotationX).toBeCloseTo(0, 5);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it("should return this for chaining", () => {
|
|
331
|
-
const camera = new Camera3D();
|
|
332
|
-
const result = camera.lookAt(0, 0, 100);
|
|
333
|
-
|
|
334
|
-
expect(result).toBe(camera);
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("isDragging", () => {
|
|
339
|
-
it("should return dragging state", () => {
|
|
340
|
-
const camera = new Camera3D();
|
|
341
|
-
|
|
342
|
-
expect(camera.isDragging()).toBe(false);
|
|
343
|
-
|
|
344
|
-
camera._isDragging = true;
|
|
345
|
-
|
|
346
|
-
expect(camera.isDragging()).toBe(true);
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe("mouse control", () => {
|
|
351
|
-
let mockCanvas;
|
|
352
|
-
|
|
353
|
-
beforeEach(() => {
|
|
354
|
-
mockCanvas = {
|
|
355
|
-
addEventListener: vi.fn(),
|
|
356
|
-
removeEventListener: vi.fn(),
|
|
357
|
-
};
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it("should enable mouse control", () => {
|
|
361
|
-
const camera = new Camera3D();
|
|
362
|
-
|
|
363
|
-
camera.enableMouseControl(mockCanvas);
|
|
364
|
-
|
|
365
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
366
|
-
"mousedown",
|
|
367
|
-
expect.any(Function),
|
|
368
|
-
);
|
|
369
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
370
|
-
"mousemove",
|
|
371
|
-
expect.any(Function),
|
|
372
|
-
);
|
|
373
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
374
|
-
"mouseup",
|
|
375
|
-
expect.any(Function),
|
|
376
|
-
);
|
|
377
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
378
|
-
"mouseleave",
|
|
379
|
-
expect.any(Function),
|
|
380
|
-
);
|
|
381
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
382
|
-
"touchstart",
|
|
383
|
-
expect.any(Function),
|
|
384
|
-
);
|
|
385
|
-
expect(mockCanvas.addEventListener).toHaveBeenCalledWith(
|
|
386
|
-
"dblclick",
|
|
387
|
-
expect.any(Function),
|
|
388
|
-
);
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
it("should disable mouse control", () => {
|
|
392
|
-
const camera = new Camera3D();
|
|
393
|
-
camera.enableMouseControl(mockCanvas);
|
|
394
|
-
|
|
395
|
-
camera.disableMouseControl();
|
|
396
|
-
|
|
397
|
-
expect(mockCanvas.removeEventListener).toHaveBeenCalledWith(
|
|
398
|
-
"mousedown",
|
|
399
|
-
expect.any(Function),
|
|
400
|
-
);
|
|
401
|
-
expect(mockCanvas.removeEventListener).toHaveBeenCalledWith(
|
|
402
|
-
"mousemove",
|
|
403
|
-
expect.any(Function),
|
|
404
|
-
);
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
it("should return this for chaining", () => {
|
|
408
|
-
const camera = new Camera3D();
|
|
409
|
-
|
|
410
|
-
expect(camera.enableMouseControl(mockCanvas)).toBe(camera);
|
|
411
|
-
expect(camera.disableMouseControl()).toBe(camera);
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
it("should disable previous control when enabling new", () => {
|
|
415
|
-
const camera = new Camera3D();
|
|
416
|
-
const mockCanvas2 = {
|
|
417
|
-
addEventListener: vi.fn(),
|
|
418
|
-
removeEventListener: vi.fn(),
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
camera.enableMouseControl(mockCanvas);
|
|
422
|
-
camera.enableMouseControl(mockCanvas2);
|
|
423
|
-
|
|
424
|
-
expect(mockCanvas.removeEventListener).toHaveBeenCalled();
|
|
425
|
-
expect(mockCanvas2.addEventListener).toHaveBeenCalled();
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
});
|