@sudobility/music_spatial_core 0.0.2 → 0.0.5
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/project.d.ts +52 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +250 -0
- package/dist/project.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './geometry';
|
|
|
2
2
|
export * from './map-math';
|
|
3
3
|
export * from './movement';
|
|
4
4
|
export * from './scene';
|
|
5
|
+
export * from './project';
|
|
5
6
|
export * from './use-throttled-commit';
|
|
6
7
|
export { effectiveUnpluggedArrangement, UNPLUGGED_RADIUS, } from '@sudobility/music_types';
|
|
7
8
|
export type { EffectiveUnpluggedArrangement } from '@sudobility/music_types';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AAMvC,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7E,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AAMvC,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7E,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './geometry';
|
|
|
2
2
|
export * from './map-math';
|
|
3
3
|
export * from './movement';
|
|
4
4
|
export * from './scene';
|
|
5
|
+
export * from './project';
|
|
5
6
|
export * from './use-throttled-commit';
|
|
6
7
|
// Re-exported for the platform packages, which already depend on
|
|
7
8
|
// music_types themselves but read these through here alongside everything
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AAEvC,iEAAiE;AACjE,0EAA0E;AAC1E,2EAA2E;AAC3E,wBAAwB;AACxB,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AAEvC,iEAAiE;AACjE,0EAA0E;AAC1E,2EAA2E;AAC3E,wBAAwB;AACxB,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SpatialScene } from './scene';
|
|
2
|
+
export interface Viewport {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
/** Vertical field of view. Default: the web canvas's 70°. */
|
|
6
|
+
readonly fovDeg?: number;
|
|
7
|
+
}
|
|
8
|
+
/** Flat `[x0, y0, x1, y1, ...]` pixel coordinates, one segment per four
|
|
9
|
+
* numbers. Flat rather than objects so a platform can hand it to a
|
|
10
|
+
* points-mode draw call or build a path string without a second pass. */
|
|
11
|
+
export type Segments = readonly number[];
|
|
12
|
+
export interface ProjectedInstrument {
|
|
13
|
+
readonly trackId: string;
|
|
14
|
+
readonly lit: boolean;
|
|
15
|
+
readonly color: string;
|
|
16
|
+
readonly litColor: string;
|
|
17
|
+
readonly segments: Segments;
|
|
18
|
+
/** 0 = in front of the listener, 1 = fully lost in the fog. */
|
|
19
|
+
readonly fade: number;
|
|
20
|
+
/** View-space distance, for painter's ordering (far first). */
|
|
21
|
+
readonly distance: number;
|
|
22
|
+
}
|
|
23
|
+
/** A batch of segments sharing one fade level, for the floor. */
|
|
24
|
+
export interface FadedSegments {
|
|
25
|
+
readonly segments: Segments;
|
|
26
|
+
readonly fade: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ProjectedScene {
|
|
29
|
+
/** The floor grid's minor lines, batched by fade. */
|
|
30
|
+
readonly floor: readonly FadedSegments[];
|
|
31
|
+
/** The two centre lines of the grid, batched by fade. */
|
|
32
|
+
readonly floorAxes: readonly FadedSegments[];
|
|
33
|
+
/** The default half-circle the instruments start on. */
|
|
34
|
+
readonly ring: readonly FadedSegments[];
|
|
35
|
+
/** Far to near, so drawing in order overpaints correctly. */
|
|
36
|
+
readonly instruments: readonly ProjectedInstrument[];
|
|
37
|
+
}
|
|
38
|
+
/** The web canvas's stage palette, so both platforms draw the same stage. */
|
|
39
|
+
export declare const STAGE_PALETTE: {
|
|
40
|
+
readonly background: "#12161d";
|
|
41
|
+
readonly gridMajor: "#3a4452";
|
|
42
|
+
readonly gridMinor: "#232a34";
|
|
43
|
+
readonly ring: "#4c5a6b";
|
|
44
|
+
};
|
|
45
|
+
/** Linear fog, as the web canvas sets it: fully clear inside `near`, gone at `far`. */
|
|
46
|
+
export declare const FOG_NEAR = 8;
|
|
47
|
+
export declare const FOG_FAR = 30;
|
|
48
|
+
export declare const DEFAULT_FOV_DEG = 70;
|
|
49
|
+
/** How faded a point at `distance` from the eye is: 0 clear, 1 gone. */
|
|
50
|
+
export declare function fogFade(distance: number): number;
|
|
51
|
+
export declare function projectScene(scene: SpatialScene, viewport: Viewport): ProjectedScene;
|
|
52
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAqB,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;0EAE0E;AAC1E,MAAM,MAAM,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;AAEzC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAC;IAC7C,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACtD;AAED,6EAA6E;AAC7E,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC;AAEX,uFAAuF;AACvF,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,eAAO,MAAM,OAAO,KAAK,CAAC;AAE1B,eAAO,MAAM,eAAe,KAAK,CAAC;AAYlC,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,QAAQ,GACjB,cAAc,CAUhB"}
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 3D stage as 2D line segments: `SpatialScene` projected through its own
|
|
3
|
+
* camera onto a viewport, for a platform that draws lines rather than
|
|
4
|
+
* running a GL rasteriser.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this exists
|
|
7
|
+
*
|
|
8
|
+
* Every instrument model is polylines (`InstrumentSpatialModel.strokes`),
|
|
9
|
+
* the floor is a grid of lines and the stage ring is a polyline, so the web
|
|
10
|
+
* view's three.js scene is, in the end, a few thousand line segments with a
|
|
11
|
+
* camera in front of them. React Native has no GL context of its own —
|
|
12
|
+
* `music_app_rn` is a bare app with macOS and Windows targets, where the
|
|
13
|
+
* one GL provider that exists (`expo-gl`) does not run — but it does have a
|
|
14
|
+
* 2D canvas on every platform. Projecting here, once, in pure math, and
|
|
15
|
+
* handing each platform "these segments, in this colour, this faded" gives
|
|
16
|
+
* every platform the same picture from the same scene, and leaves nothing
|
|
17
|
+
* platform-specific to get the camera wrong in.
|
|
18
|
+
*
|
|
19
|
+
* ## What it mirrors
|
|
20
|
+
*
|
|
21
|
+
* `buildScene` already speaks three.js: right-handed, x mirrored, camera
|
|
22
|
+
* looking down its local -z, `rotation` as an XYZ Euler. This module uses
|
|
23
|
+
* three's own `Matrix4`/`Euler` to compose the transforms so the projection
|
|
24
|
+
* agrees with the GL view to the last sign — re-deriving rotation matrices
|
|
25
|
+
* by hand would be a second, riskier way to compute the same thing (the
|
|
26
|
+
* same reasoning `geometry.ts` gives for not baking poses). The fog is the
|
|
27
|
+
* web canvas's linear fog, applied as a per-segment fade for the floor
|
|
28
|
+
* (whose lines run the whole depth of the stage) and per instrument
|
|
29
|
+
* (small enough that one distance describes it).
|
|
30
|
+
*/
|
|
31
|
+
import { Euler, Matrix4, Quaternion, Vector3 } from 'three';
|
|
32
|
+
import { UNPLUGGED_RADIUS } from '@sudobility/music_types';
|
|
33
|
+
/** The web canvas's stage palette, so both platforms draw the same stage. */
|
|
34
|
+
export const STAGE_PALETTE = {
|
|
35
|
+
background: '#12161d',
|
|
36
|
+
gridMajor: '#3a4452',
|
|
37
|
+
gridMinor: '#232a34',
|
|
38
|
+
ring: '#4c5a6b',
|
|
39
|
+
};
|
|
40
|
+
/** Linear fog, as the web canvas sets it: fully clear inside `near`, gone at `far`. */
|
|
41
|
+
export const FOG_NEAR = 8;
|
|
42
|
+
export const FOG_FAR = 30;
|
|
43
|
+
export const DEFAULT_FOV_DEG = 70;
|
|
44
|
+
/** Anything nearer the eye than this is clipped, as the web camera's `near`. */
|
|
45
|
+
const NEAR_PLANE = 0.05;
|
|
46
|
+
/** The floor grid: `GRID_SIZE` metres square, one line per metre — the web's `gridHelper(40, 40)`. */
|
|
47
|
+
const GRID_SIZE = 40;
|
|
48
|
+
const GRID_DIVISIONS = 40;
|
|
49
|
+
/** How many fade levels the floor is batched into. */
|
|
50
|
+
const FADE_STEPS = 8;
|
|
51
|
+
const RING_SEGMENTS = 48;
|
|
52
|
+
const RING_Y = 0.005;
|
|
53
|
+
/** How faded a point at `distance` from the eye is: 0 clear, 1 gone. */
|
|
54
|
+
export function fogFade(distance) {
|
|
55
|
+
const t = (distance - FOG_NEAR) / (FOG_FAR - FOG_NEAR);
|
|
56
|
+
return t <= 0 ? 0 : t >= 1 ? 1 : t;
|
|
57
|
+
}
|
|
58
|
+
export function projectScene(scene, viewport) {
|
|
59
|
+
const projector = new Projector(scene, viewport);
|
|
60
|
+
return {
|
|
61
|
+
floor: projector.floor(false),
|
|
62
|
+
floorAxes: projector.floor(true),
|
|
63
|
+
ring: projector.ring(),
|
|
64
|
+
instruments: scene.instruments
|
|
65
|
+
.map(instrument => projector.instrument(instrument))
|
|
66
|
+
.sort((a, b) => b.distance - a.distance),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
class Projector {
|
|
70
|
+
constructor(scene, viewport) {
|
|
71
|
+
Object.defineProperty(this, "view", {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: true,
|
|
74
|
+
writable: true,
|
|
75
|
+
value: new Matrix4()
|
|
76
|
+
});
|
|
77
|
+
Object.defineProperty(this, "halfWidth", {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true,
|
|
80
|
+
writable: true,
|
|
81
|
+
value: void 0
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(this, "halfHeight", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: void 0
|
|
88
|
+
});
|
|
89
|
+
/** Pixels per unit of x/z over -z_view, from the field of view. */
|
|
90
|
+
Object.defineProperty(this, "focalY", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
configurable: true,
|
|
93
|
+
writable: true,
|
|
94
|
+
value: void 0
|
|
95
|
+
});
|
|
96
|
+
Object.defineProperty(this, "focalX", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
configurable: true,
|
|
99
|
+
writable: true,
|
|
100
|
+
value: void 0
|
|
101
|
+
});
|
|
102
|
+
Object.defineProperty(this, "eye", {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
configurable: true,
|
|
105
|
+
writable: true,
|
|
106
|
+
value: void 0
|
|
107
|
+
});
|
|
108
|
+
const fov = ((viewport.fovDeg ?? DEFAULT_FOV_DEG) * Math.PI) / 180;
|
|
109
|
+
this.halfWidth = viewport.width / 2;
|
|
110
|
+
this.halfHeight = viewport.height / 2;
|
|
111
|
+
// A vertical field of view: the top of the view is tan(fov/2) units up
|
|
112
|
+
// per unit of depth, whatever the aspect, so the horizontal extent
|
|
113
|
+
// follows from the pixel aspect exactly as three's PerspectiveCamera.
|
|
114
|
+
this.focalY = this.halfHeight / Math.tan(fov / 2);
|
|
115
|
+
this.focalX = this.focalY;
|
|
116
|
+
const [cx, cy, cz] = scene.camera.position;
|
|
117
|
+
const [rx, ry, rz] = scene.camera.rotation;
|
|
118
|
+
this.eye = new Vector3(cx, cy, cz);
|
|
119
|
+
const cameraWorld = new Matrix4().compose(this.eye, new Quaternion().setFromEuler(new Euler(rx, ry, rz, 'XYZ')), new Vector3(1, 1, 1));
|
|
120
|
+
this.view.copy(cameraWorld).invert();
|
|
121
|
+
}
|
|
122
|
+
instrument(instrument) {
|
|
123
|
+
const [px, py, pz] = instrument.position;
|
|
124
|
+
const [rx, ry, rz] = instrument.rotation;
|
|
125
|
+
const model = new Matrix4().compose(new Vector3(px, py, pz), new Quaternion().setFromEuler(new Euler(rx, ry, rz, 'XYZ')), new Vector3(instrument.scale, instrument.scale, instrument.scale));
|
|
126
|
+
const modelView = new Matrix4().multiplyMatrices(this.view, model);
|
|
127
|
+
const segments = [];
|
|
128
|
+
const a = new Vector3();
|
|
129
|
+
const b = new Vector3();
|
|
130
|
+
for (const geometry of instrument.geometry) {
|
|
131
|
+
const positions = geometry.getAttribute('position');
|
|
132
|
+
for (let i = 0; i + 1 < positions.count; i += 2) {
|
|
133
|
+
a.fromBufferAttribute(positions, i).applyMatrix4(modelView);
|
|
134
|
+
b.fromBufferAttribute(positions, i + 1).applyMatrix4(modelView);
|
|
135
|
+
this.pushSegment(segments, a, b);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const distance = this.eye.distanceTo(new Vector3(px, py, pz));
|
|
139
|
+
return {
|
|
140
|
+
trackId: instrument.trackId,
|
|
141
|
+
lit: instrument.lit,
|
|
142
|
+
color: instrument.color,
|
|
143
|
+
litColor: instrument.litColor,
|
|
144
|
+
segments,
|
|
145
|
+
fade: fogFade(distance),
|
|
146
|
+
distance,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** The grid, one metre a segment so the fog can vary along a line. */
|
|
150
|
+
floor(axesOnly) {
|
|
151
|
+
const half = GRID_SIZE / 2;
|
|
152
|
+
const step = GRID_SIZE / GRID_DIVISIONS;
|
|
153
|
+
const buckets = new FadeBuckets();
|
|
154
|
+
const a = new Vector3();
|
|
155
|
+
const b = new Vector3();
|
|
156
|
+
for (let i = 0; i <= GRID_DIVISIONS; i++) {
|
|
157
|
+
const k = -half + i * step;
|
|
158
|
+
const isAxis = k === 0;
|
|
159
|
+
if (isAxis !== axesOnly)
|
|
160
|
+
continue;
|
|
161
|
+
for (let j = 0; j < GRID_DIVISIONS; j++) {
|
|
162
|
+
const s = -half + j * step;
|
|
163
|
+
// A line along z at x = k, then along x at z = k.
|
|
164
|
+
a.set(k, 0, s);
|
|
165
|
+
b.set(k, 0, s + step);
|
|
166
|
+
this.pushWorldSegment(buckets, a, b);
|
|
167
|
+
a.set(s, 0, k);
|
|
168
|
+
b.set(s + step, 0, k);
|
|
169
|
+
this.pushWorldSegment(buckets, a, b);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return buckets.batches();
|
|
173
|
+
}
|
|
174
|
+
ring() {
|
|
175
|
+
const buckets = new FadeBuckets();
|
|
176
|
+
const a = new Vector3();
|
|
177
|
+
const b = new Vector3();
|
|
178
|
+
for (let i = 0; i < RING_SEGMENTS; i++) {
|
|
179
|
+
const a0 = (Math.PI * i) / RING_SEGMENTS;
|
|
180
|
+
const a1 = (Math.PI * (i + 1)) / RING_SEGMENTS;
|
|
181
|
+
a.set(Math.cos(a0) * UNPLUGGED_RADIUS, RING_Y, Math.sin(a0) * UNPLUGGED_RADIUS);
|
|
182
|
+
b.set(Math.cos(a1) * UNPLUGGED_RADIUS, RING_Y, Math.sin(a1) * UNPLUGGED_RADIUS);
|
|
183
|
+
this.pushWorldSegment(buckets, a, b);
|
|
184
|
+
}
|
|
185
|
+
return buckets.batches();
|
|
186
|
+
}
|
|
187
|
+
pushWorldSegment(buckets, a, b) {
|
|
188
|
+
const fade = fogFade(this.eye.distanceTo(new Vector3((a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2)));
|
|
189
|
+
if (fade >= 1)
|
|
190
|
+
return;
|
|
191
|
+
a.applyMatrix4(this.view);
|
|
192
|
+
b.applyMatrix4(this.view);
|
|
193
|
+
this.pushSegment(buckets.for(fade), a, b);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* One view-space segment to pixels, clipped to the near plane: a segment
|
|
197
|
+
* crossing it is cut at the plane rather than dropped, so a floor line
|
|
198
|
+
* running under the listener's feet still reaches the bottom of the view,
|
|
199
|
+
* and one wholly behind the eye is not drawn at all — projecting a point
|
|
200
|
+
* behind the camera flips it through the origin, which is the scribble a
|
|
201
|
+
* naive projector draws when the listener stands inside the stage.
|
|
202
|
+
*/
|
|
203
|
+
pushSegment(out, a, b) {
|
|
204
|
+
// View space looks down -z; "in front" is z < -NEAR_PLANE.
|
|
205
|
+
const aIn = a.z < -NEAR_PLANE;
|
|
206
|
+
const bIn = b.z < -NEAR_PLANE;
|
|
207
|
+
if (!aIn && !bIn)
|
|
208
|
+
return;
|
|
209
|
+
if (!aIn || !bIn) {
|
|
210
|
+
const t = (-NEAR_PLANE - a.z) / (b.z - a.z);
|
|
211
|
+
const cx = a.x + (b.x - a.x) * t;
|
|
212
|
+
const cy = a.y + (b.y - a.y) * t;
|
|
213
|
+
if (aIn)
|
|
214
|
+
b.set(cx, cy, -NEAR_PLANE);
|
|
215
|
+
else
|
|
216
|
+
a.set(cx, cy, -NEAR_PLANE);
|
|
217
|
+
}
|
|
218
|
+
out.push(this.halfWidth + (a.x / -a.z) * this.focalX, this.halfHeight - (a.y / -a.z) * this.focalY, this.halfWidth + (b.x / -b.z) * this.focalX, this.halfHeight - (b.y / -b.z) * this.focalY);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Segments grouped into `FADE_STEPS` fade levels, so a platform draws the
|
|
222
|
+
* floor in a handful of calls rather than one per segment. */
|
|
223
|
+
class FadeBuckets {
|
|
224
|
+
constructor() {
|
|
225
|
+
Object.defineProperty(this, "buckets", {
|
|
226
|
+
enumerable: true,
|
|
227
|
+
configurable: true,
|
|
228
|
+
writable: true,
|
|
229
|
+
value: new Map()
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
for(fade) {
|
|
233
|
+
const level = Math.min(FADE_STEPS - 1, Math.floor(fade * FADE_STEPS));
|
|
234
|
+
let bucket = this.buckets.get(level);
|
|
235
|
+
if (!bucket) {
|
|
236
|
+
bucket = [];
|
|
237
|
+
this.buckets.set(level, bucket);
|
|
238
|
+
}
|
|
239
|
+
return bucket;
|
|
240
|
+
}
|
|
241
|
+
batches() {
|
|
242
|
+
return [...this.buckets.entries()]
|
|
243
|
+
.sort((x, y) => y[0] - x[0])
|
|
244
|
+
.map(([level, segments]) => ({
|
|
245
|
+
segments,
|
|
246
|
+
fade: (level + 0.5) / FADE_STEPS,
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/music_spatial_core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Platform-agnostic engine behind the Moosiac Spatial view: instrument geometry, scene composition, camera/listener math, movement, and map-overlay math shared by music_spatial and music_spatial_rn.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@sudobility/music_types": "^0.13.
|
|
34
|
+
"@sudobility/music_types": "^0.13.40",
|
|
35
35
|
"react": ">=18",
|
|
36
36
|
"three": "^0.160.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@eslint/js": "^9.38.0",
|
|
40
|
-
"@sudobility/music_types": "^0.13.
|
|
40
|
+
"@sudobility/music_types": "^0.13.40",
|
|
41
41
|
"@testing-library/react": "^16.0.0",
|
|
42
42
|
"@types/react": "^19.2.18",
|
|
43
43
|
"@types/react-dom": "^19.2.0",
|