@pluot/core 0.1.0 → 0.1.1
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/README.md +1 -0
- package/dist/index.js +1109 -4101
- package/dist-tsc/functional-3d-view-controls.d.ts +11 -0
- package/dist-tsc/functional-3d-view-controls.d.ts.map +1 -0
- package/dist-tsc/functional-3d-view-controls.js +517 -0
- package/dist-tsc/functional-dom-2d-camera.d.ts +9 -0
- package/dist-tsc/functional-dom-2d-camera.d.ts.map +1 -0
- package/dist-tsc/functional-dom-2d-camera.js +178 -0
- package/dist-tsc/index.d.ts +2 -2
- package/dist-tsc/index.d.ts.map +1 -1
- package/dist-tsc/index.js +2 -2
- package/dist-tsc/lru-store.d.ts.map +1 -1
- package/dist-tsc/lru-store.js +3 -0
- package/dist-tsc/unrolled-3d-view-controls.d.ts +2 -0
- package/dist-tsc/unrolled-3d-view-controls.d.ts.map +1 -0
- package/dist-tsc/unrolled-3d-view-controls.js +637 -0
- package/dist-tsc/unrolled-dom-2d-camera.d.ts +2 -0
- package/dist-tsc/unrolled-dom-2d-camera.d.ts.map +1 -0
- package/dist-tsc/unrolled-dom-2d-camera.js +193 -0
- package/dist-tsc/viewport.d.ts +91 -0
- package/dist-tsc/viewport.d.ts.map +1 -1
- package/dist-tsc/viewport.js +91 -3
- package/dist-tsc/viewport.test.d.ts +2 -0
- package/dist-tsc/viewport.test.d.ts.map +1 -0
- package/dist-tsc/viewport.test.js +184 -0
- package/package.json +8 -2
- package/src/functional-3d-view-controls.ts +585 -0
- package/src/functional-dom-2d-camera.ts +214 -0
- package/src/index.ts +2 -2
- package/src/lru-store.ts +3 -0
- package/src/viewport.test.ts +262 -0
- package/src/viewport.ts +91 -3
- package/src/3d-view-controls.js +0 -271
- package/src/dom-2d-camera.js +0 -441
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
// Imports kept (analog of gl-matrix in the 2D version):
|
|
2
|
+
// gl-mat4 / gl-vec3 — low-level matrix/vector math
|
|
3
|
+
// filtered-vector — smoothed state container used by every controller
|
|
4
|
+
// binary-search-bounds, mat4-interpolate, cubic-hermite — utility primitives
|
|
5
|
+
import mat4FromQuat from "gl-mat4/fromQuat";
|
|
6
|
+
import mat4Invert from "gl-mat4/invert";
|
|
7
|
+
import mat4Rotate from "gl-mat4/rotate";
|
|
8
|
+
import mat4RotateX from "gl-mat4/rotateX";
|
|
9
|
+
import mat4RotateY from "gl-mat4/rotateY";
|
|
10
|
+
import mat4RotateZ from "gl-mat4/rotateZ";
|
|
11
|
+
import mat4Translate from "gl-mat4/translate";
|
|
12
|
+
import mat4Interpolate from "mat4-interpolate";
|
|
13
|
+
import vec3Cross from "gl-vec3/cross";
|
|
14
|
+
import vec3Normalize from "gl-vec3/normalize";
|
|
15
|
+
import bsearch from "binary-search-bounds";
|
|
16
|
+
// Closure state inherited from 3d-view-controls.js (initialized elsewhere):
|
|
17
|
+
// element — DOM node the listeners are on
|
|
18
|
+
// camera = { flipX, flipY, rotateSpeed, zoomSpeed, translateSpeed, ... }
|
|
19
|
+
// distance — number, recomputed by tick()
|
|
20
|
+
// view — 3d-view ViewController:
|
|
21
|
+
// view._controllerList = [turntable, orbit, matrix] // sub-controllers
|
|
22
|
+
// view._active // one of the three
|
|
23
|
+
// view.lastT() — Math.max(_active.lastT, ...)
|
|
24
|
+
//
|
|
25
|
+
// State owned by mouse-change/mouse-listen.js (one instance, captured in the
|
|
26
|
+
// closure of `mouseChange(element, handleInteraction)`):
|
|
27
|
+
// buttonState, mcX, mcY — last reported (buttons, x, y)
|
|
28
|
+
// mcMods = { shift, alt, control, meta }
|
|
29
|
+
//
|
|
30
|
+
// State owned by 3d-view-controls.js itself:
|
|
31
|
+
// lastX, lastY, lastMods — previous (x, y, mods) for handleInteraction
|
|
32
|
+
//
|
|
33
|
+
// State owned by mouse-wheel/wheel.js:
|
|
34
|
+
// lineHeight = toPX('ex', element) — computed once at listener attach
|
|
35
|
+
//
|
|
36
|
+
// One-shot init:
|
|
37
|
+
// const now = (performance && performance.now)
|
|
38
|
+
// ? () => performance.now()
|
|
39
|
+
// : (Date.now || (() => +new Date()));
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Helpers inlined from orbit-camera-controller/orbit.js
|
|
42
|
+
// (these are file-local helpers, not exports — duplicated here so the
|
|
43
|
+
// controller method bodies below can stay close to their originals).
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
function len3(x, y, z) {
|
|
46
|
+
return Math.sqrt(x * x + y * y + z * z);
|
|
47
|
+
}
|
|
48
|
+
function len4(w, x, y, z) {
|
|
49
|
+
return Math.sqrt(w * w + x * x + y * y + z * z);
|
|
50
|
+
}
|
|
51
|
+
function normalize4(out, a) {
|
|
52
|
+
const ax = a[0], ay = a[1], az = a[2], aw = a[3];
|
|
53
|
+
const al = len4(ax, ay, az, aw);
|
|
54
|
+
if (al > 1e-6) {
|
|
55
|
+
out[0] = ax / al;
|
|
56
|
+
out[1] = ay / al;
|
|
57
|
+
out[2] = az / al;
|
|
58
|
+
out[3] = aw / al;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
out[0] = out[1] = out[2] = 0.0;
|
|
62
|
+
out[3] = 1.0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Inlined from filtered-vector/fvec.js — methods used by the controllers.
|
|
67
|
+
// `cubicHermite` is kept as an import (analog of gl-matrix), called via
|
|
68
|
+
// the global helper below.
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
function fvSet(fv, t /* , ...components */) {
|
|
71
|
+
// Inlined: FilteredVector.prototype.set
|
|
72
|
+
const d = fv.dimension;
|
|
73
|
+
if (t < fv._time[fv._time.length - 1] || arguments.length !== d + 2)
|
|
74
|
+
return;
|
|
75
|
+
const state = fv._state;
|
|
76
|
+
const velocity = fv._velocity;
|
|
77
|
+
const lo = fv.bounds[0];
|
|
78
|
+
const hi = fv.bounds[1];
|
|
79
|
+
fv._time.push(t);
|
|
80
|
+
for (let i = d; i > 0; --i) {
|
|
81
|
+
const x = arguments[i + 1];
|
|
82
|
+
state.push(Math.min(hi[i - 1], Math.max(lo[i - 1], x)));
|
|
83
|
+
velocity.push(0);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function fvMove(fv, t /* , ...deltas */) {
|
|
87
|
+
// Inlined: FilteredVector.prototype.move
|
|
88
|
+
const t0 = fv._time[fv._time.length - 1];
|
|
89
|
+
const d = fv.dimension;
|
|
90
|
+
if (t <= t0 || arguments.length !== d + 2)
|
|
91
|
+
return;
|
|
92
|
+
const state = fv._state;
|
|
93
|
+
const velocity = fv._velocity;
|
|
94
|
+
let statePtr = state.length - d;
|
|
95
|
+
const lo = fv.bounds[0];
|
|
96
|
+
const hi = fv.bounds[1];
|
|
97
|
+
const dt = t - t0;
|
|
98
|
+
const sf = dt > 1e-6 ? 1 / dt : 0.0;
|
|
99
|
+
fv._time.push(t);
|
|
100
|
+
for (let i = d; i > 0; --i) {
|
|
101
|
+
const dx = arguments[i + 1];
|
|
102
|
+
const next = state[statePtr++] + dx;
|
|
103
|
+
state.push(Math.min(hi[i - 1], Math.max(lo[i - 1], next)));
|
|
104
|
+
velocity.push(dx * sf);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// `fv.curve(t)` mutates fv._scratch[0] and returns it. Every controller's
|
|
108
|
+
// `computedX` field is aliased to that same Float array, so calling curve()
|
|
109
|
+
// is what refreshes the controller's `computedRadius`, `computedCenter`, etc.
|
|
110
|
+
// curve() depends on `cubic-hermite` which is kept as an import.
|
|
111
|
+
import cubicHermite from "cubic-hermite";
|
|
112
|
+
function fvCurve(fv, t) {
|
|
113
|
+
const time = fv._time;
|
|
114
|
+
const n = time.length;
|
|
115
|
+
const idx = bsearch.le(time, t);
|
|
116
|
+
const result = fv._scratch[0];
|
|
117
|
+
const state = fv._state;
|
|
118
|
+
const velocity = fv._velocity;
|
|
119
|
+
const d = fv.dimension;
|
|
120
|
+
const bounds = fv.bounds;
|
|
121
|
+
if (idx < 0) {
|
|
122
|
+
let ptr = d - 1;
|
|
123
|
+
for (let i = 0; i < d; ++i, --ptr)
|
|
124
|
+
result[i] = state[ptr];
|
|
125
|
+
}
|
|
126
|
+
else if (idx >= n - 1) {
|
|
127
|
+
let ptr = state.length - 1;
|
|
128
|
+
const tf = t - time[n - 1];
|
|
129
|
+
for (let i = 0; i < d; ++i, --ptr)
|
|
130
|
+
result[i] = state[ptr] + tf * velocity[ptr];
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
let ptr = d * (idx + 1) - 1;
|
|
134
|
+
const t0 = time[idx];
|
|
135
|
+
const t1 = time[idx + 1];
|
|
136
|
+
const dt = t1 - t0 || 1.0;
|
|
137
|
+
const x0 = fv._scratch[1];
|
|
138
|
+
const x1 = fv._scratch[2];
|
|
139
|
+
const v0 = fv._scratch[3];
|
|
140
|
+
const v1 = fv._scratch[4];
|
|
141
|
+
let steady = true;
|
|
142
|
+
for (let i = 0; i < d; ++i, --ptr) {
|
|
143
|
+
x0[i] = state[ptr];
|
|
144
|
+
v0[i] = velocity[ptr] * dt;
|
|
145
|
+
x1[i] = state[ptr + d];
|
|
146
|
+
v1[i] = velocity[ptr + d] * dt;
|
|
147
|
+
steady = steady && x0[i] === x1[i] && v0[i] === v1[i] && v0[i] === 0.0;
|
|
148
|
+
}
|
|
149
|
+
if (steady) {
|
|
150
|
+
for (let i = 0; i < d; ++i)
|
|
151
|
+
result[i] = x0[i];
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
cubicHermite(x0, v0, x1, v1, (t - t0) / dt, result);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const lo = bounds[0];
|
|
158
|
+
const hi = bounds[1];
|
|
159
|
+
for (let i = 0; i < d; ++i) {
|
|
160
|
+
result[i] = Math.min(hi[i], Math.max(lo[i], result[i]));
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Inlined from orbit-camera-controller/orbit.js
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
function orbitRecalcMatrix(c, t) {
|
|
168
|
+
fvCurve(c.radius, t);
|
|
169
|
+
fvCurve(c.center, t);
|
|
170
|
+
fvCurve(c.rotation, t);
|
|
171
|
+
const quat = c.computedRotation;
|
|
172
|
+
normalize4(quat, quat);
|
|
173
|
+
const mat = c.computedMatrix;
|
|
174
|
+
mat4FromQuat(mat, quat);
|
|
175
|
+
const center = c.computedCenter;
|
|
176
|
+
const eye = c.computedEye;
|
|
177
|
+
const up = c.computedUp;
|
|
178
|
+
const radius = Math.exp(c.computedRadius[0]);
|
|
179
|
+
eye[0] = center[0] + radius * mat[2];
|
|
180
|
+
eye[1] = center[1] + radius * mat[6];
|
|
181
|
+
eye[2] = center[2] + radius * mat[10];
|
|
182
|
+
up[0] = mat[1];
|
|
183
|
+
up[1] = mat[5];
|
|
184
|
+
up[2] = mat[9];
|
|
185
|
+
for (let i = 0; i < 3; ++i) {
|
|
186
|
+
let rr = 0.0;
|
|
187
|
+
for (let j = 0; j < 3; ++j)
|
|
188
|
+
rr += mat[i + 4 * j] * eye[j];
|
|
189
|
+
mat[12 + i] = -rr;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function orbitRotate(c, t, dx, dy, dz) {
|
|
193
|
+
orbitRecalcMatrix(c, t);
|
|
194
|
+
dx = dx || 0.0;
|
|
195
|
+
dy = dy || 0.0;
|
|
196
|
+
const mat = c.computedMatrix;
|
|
197
|
+
const rx = mat[0], ry = mat[4], rz = mat[8];
|
|
198
|
+
const ux = mat[1], uy = mat[5], uz = mat[9];
|
|
199
|
+
const fx = mat[2], fy = mat[6], fz = mat[10];
|
|
200
|
+
const qx = dx * rx + dy * ux;
|
|
201
|
+
const qy = dx * ry + dy * uy;
|
|
202
|
+
const qz = dx * rz + dy * uz;
|
|
203
|
+
let bx = -(fy * qz - fz * qy);
|
|
204
|
+
let by = -(fz * qx - fx * qz);
|
|
205
|
+
let bz = -(fx * qy - fy * qx);
|
|
206
|
+
let bw = Math.sqrt(Math.max(0.0, 1.0 - bx * bx - by * by - bz * bz));
|
|
207
|
+
let bl = len4(bx, by, bz, bw);
|
|
208
|
+
if (bl > 1e-6) {
|
|
209
|
+
bx /= bl;
|
|
210
|
+
by /= bl;
|
|
211
|
+
bz /= bl;
|
|
212
|
+
bw /= bl;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
bx = by = bz = 0.0;
|
|
216
|
+
bw = 1.0;
|
|
217
|
+
}
|
|
218
|
+
const rotation = c.computedRotation;
|
|
219
|
+
const ax = rotation[0], ay = rotation[1], az = rotation[2], aw = rotation[3];
|
|
220
|
+
let cx = ax * bw + aw * bx + ay * bz - az * by;
|
|
221
|
+
let cy = ay * bw + aw * by + az * bx - ax * bz;
|
|
222
|
+
let cz = az * bw + aw * bz + ax * by - ay * bx;
|
|
223
|
+
let cw = aw * bw - ax * bx - ay * by - az * bz;
|
|
224
|
+
// Apply roll
|
|
225
|
+
if (dz) {
|
|
226
|
+
bx = fx;
|
|
227
|
+
by = fy;
|
|
228
|
+
bz = fz;
|
|
229
|
+
const s = Math.sin(dz) / len3(bx, by, bz);
|
|
230
|
+
bx *= s;
|
|
231
|
+
by *= s;
|
|
232
|
+
bz *= s;
|
|
233
|
+
bw = Math.cos(dx);
|
|
234
|
+
cx = cx * bw + cw * bx + cy * bz - cz * by;
|
|
235
|
+
cy = cy * bw + cw * by + cz * bx - cx * bz;
|
|
236
|
+
cz = cz * bw + cw * bz + cx * by - cy * bx;
|
|
237
|
+
cw = cw * bw - cx * bx - cy * by - cz * bz;
|
|
238
|
+
}
|
|
239
|
+
const cl = len4(cx, cy, cz, cw);
|
|
240
|
+
if (cl > 1e-6) {
|
|
241
|
+
cx /= cl;
|
|
242
|
+
cy /= cl;
|
|
243
|
+
cz /= cl;
|
|
244
|
+
cw /= cl;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
cx = cy = cz = 0.0;
|
|
248
|
+
cw = 1.0;
|
|
249
|
+
}
|
|
250
|
+
fvSet(c.rotation, t, cx, cy, cz, cw);
|
|
251
|
+
}
|
|
252
|
+
function orbitPan(c, t, dx, dy, dz) {
|
|
253
|
+
dx = dx || 0.0;
|
|
254
|
+
dy = dy || 0.0;
|
|
255
|
+
dz = dz || 0.0;
|
|
256
|
+
orbitRecalcMatrix(c, t);
|
|
257
|
+
const mat = c.computedMatrix;
|
|
258
|
+
let ux = mat[1], uy = mat[5], uz = mat[9];
|
|
259
|
+
const ul = len3(ux, uy, uz);
|
|
260
|
+
ux /= ul;
|
|
261
|
+
uy /= ul;
|
|
262
|
+
uz /= ul;
|
|
263
|
+
let rx = mat[0], ry = mat[4], rz = mat[8];
|
|
264
|
+
const ru = rx * ux + ry * uy + rz * uz;
|
|
265
|
+
rx -= ux * ru;
|
|
266
|
+
ry -= uy * ru;
|
|
267
|
+
rz -= uz * ru;
|
|
268
|
+
const rl = len3(rx, ry, rz);
|
|
269
|
+
rx /= rl;
|
|
270
|
+
ry /= rl;
|
|
271
|
+
rz /= rl;
|
|
272
|
+
// fx,fy,fz computed in the original orbit.pan but never used after
|
|
273
|
+
// ortho-projection — left out (and present in the original as dead code).
|
|
274
|
+
const vx = rx * dx + ux * dy;
|
|
275
|
+
const vy = ry * dx + uy * dy;
|
|
276
|
+
const vz = rz * dx + uz * dy;
|
|
277
|
+
fvMove(c.center, t, vx, vy, vz);
|
|
278
|
+
// Update z-component of radius
|
|
279
|
+
let radius = Math.exp(c.computedRadius[0]);
|
|
280
|
+
radius = Math.max(1e-4, radius + dz);
|
|
281
|
+
fvSet(c.radius, t, Math.log(radius));
|
|
282
|
+
}
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
// Inlined from turntable-camera-controller/turntable.js
|
|
285
|
+
// ---------------------------------------------------------------------------
|
|
286
|
+
const turntableZAxis = [0, 0, 0];
|
|
287
|
+
function turntableRecalcMatrix(c, t) {
|
|
288
|
+
fvCurve(c.center, t);
|
|
289
|
+
fvCurve(c.up, t);
|
|
290
|
+
fvCurve(c.right, t);
|
|
291
|
+
fvCurve(c.radius, t);
|
|
292
|
+
fvCurve(c.angle, t);
|
|
293
|
+
const up = c.computedUp;
|
|
294
|
+
const right = c.computedRight;
|
|
295
|
+
let uu = 0.0, ur = 0.0;
|
|
296
|
+
for (let i = 0; i < 3; ++i) {
|
|
297
|
+
ur += up[i] * right[i];
|
|
298
|
+
uu += up[i] * up[i];
|
|
299
|
+
}
|
|
300
|
+
const ul = Math.sqrt(uu);
|
|
301
|
+
let rr = 0.0;
|
|
302
|
+
for (let i = 0; i < 3; ++i) {
|
|
303
|
+
right[i] -= up[i] * ur / uu;
|
|
304
|
+
rr += right[i] * right[i];
|
|
305
|
+
up[i] /= ul;
|
|
306
|
+
}
|
|
307
|
+
const rl = Math.sqrt(rr);
|
|
308
|
+
for (let i = 0; i < 3; ++i)
|
|
309
|
+
right[i] /= rl;
|
|
310
|
+
const toward = c.computedToward;
|
|
311
|
+
vec3Cross(toward, up, right);
|
|
312
|
+
vec3Normalize(toward, toward);
|
|
313
|
+
const radius = Math.exp(c.computedRadius[0]);
|
|
314
|
+
const theta = c.computedAngle[0];
|
|
315
|
+
const phi = c.computedAngle[1];
|
|
316
|
+
const ctheta = Math.cos(theta), stheta = Math.sin(theta);
|
|
317
|
+
const cphi = Math.cos(phi), sphi = Math.sin(phi);
|
|
318
|
+
const center = c.computedCenter;
|
|
319
|
+
const wx = ctheta * cphi, wy = stheta * cphi, wz = sphi;
|
|
320
|
+
const sx = -ctheta * sphi, sy = -stheta * sphi, sz = cphi;
|
|
321
|
+
const eye = c.computedEye;
|
|
322
|
+
const mat = c.computedMatrix;
|
|
323
|
+
for (let i = 0; i < 3; ++i) {
|
|
324
|
+
const x = wx * right[i] + wy * toward[i] + wz * up[i];
|
|
325
|
+
mat[4 * i + 1] = sx * right[i] + sy * toward[i] + sz * up[i];
|
|
326
|
+
mat[4 * i + 2] = x;
|
|
327
|
+
mat[4 * i + 3] = 0.0;
|
|
328
|
+
}
|
|
329
|
+
const ax = mat[1], ay = mat[5], az = mat[9];
|
|
330
|
+
const bx = mat[2], by = mat[6], bz = mat[10];
|
|
331
|
+
let cx = ay * bz - az * by;
|
|
332
|
+
let cy = az * bx - ax * bz;
|
|
333
|
+
let cz = ax * by - ay * bx;
|
|
334
|
+
const cl = len3(cx, cy, cz);
|
|
335
|
+
cx /= cl;
|
|
336
|
+
cy /= cl;
|
|
337
|
+
cz /= cl;
|
|
338
|
+
mat[0] = cx;
|
|
339
|
+
mat[4] = cy;
|
|
340
|
+
mat[8] = cz;
|
|
341
|
+
for (let i = 0; i < 3; ++i)
|
|
342
|
+
eye[i] = center[i] + mat[2 + 4 * i] * radius;
|
|
343
|
+
for (let i = 0; i < 3; ++i) {
|
|
344
|
+
let r = 0.0;
|
|
345
|
+
for (let j = 0; j < 3; ++j)
|
|
346
|
+
r += mat[i + 4 * j] * eye[j];
|
|
347
|
+
mat[12 + i] = -r;
|
|
348
|
+
}
|
|
349
|
+
mat[15] = 1.0;
|
|
350
|
+
}
|
|
351
|
+
function turntableRotate(c, t, dtheta, dphi, droll) {
|
|
352
|
+
fvMove(c.angle, t, dtheta, dphi);
|
|
353
|
+
if (droll) {
|
|
354
|
+
turntableRecalcMatrix(c, t);
|
|
355
|
+
const mat = c.computedMatrix;
|
|
356
|
+
turntableZAxis[0] = mat[2];
|
|
357
|
+
turntableZAxis[1] = mat[6];
|
|
358
|
+
turntableZAxis[2] = mat[10];
|
|
359
|
+
const up = c.computedUp;
|
|
360
|
+
const right = c.computedRight;
|
|
361
|
+
const toward = c.computedToward;
|
|
362
|
+
for (let i = 0; i < 3; ++i) {
|
|
363
|
+
mat[4 * i] = up[i];
|
|
364
|
+
mat[4 * i + 1] = right[i];
|
|
365
|
+
mat[4 * i + 2] = toward[i];
|
|
366
|
+
}
|
|
367
|
+
mat4Rotate(mat, mat, droll, turntableZAxis);
|
|
368
|
+
for (let i = 0; i < 3; ++i) {
|
|
369
|
+
up[i] = mat[4 * i];
|
|
370
|
+
right[i] = mat[4 * i + 1];
|
|
371
|
+
}
|
|
372
|
+
fvSet(c.up, t, up[0], up[1], up[2]);
|
|
373
|
+
fvSet(c.right, t, right[0], right[1], right[2]);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function turntablePan(c, t, dx, dy, dz) {
|
|
377
|
+
dx = dx || 0.0;
|
|
378
|
+
dy = dy || 0.0;
|
|
379
|
+
dz = dz || 0.0;
|
|
380
|
+
turntableRecalcMatrix(c, t);
|
|
381
|
+
const mat = c.computedMatrix;
|
|
382
|
+
let ux = mat[1], uy = mat[5], uz = mat[9];
|
|
383
|
+
const ul = len3(ux, uy, uz);
|
|
384
|
+
ux /= ul;
|
|
385
|
+
uy /= ul;
|
|
386
|
+
uz /= ul;
|
|
387
|
+
let rx = mat[0], ry = mat[4], rz = mat[8];
|
|
388
|
+
const ru = rx * ux + ry * uy + rz * uz;
|
|
389
|
+
rx -= ux * ru;
|
|
390
|
+
ry -= uy * ru;
|
|
391
|
+
rz -= uz * ru;
|
|
392
|
+
const rl = len3(rx, ry, rz);
|
|
393
|
+
rx /= rl;
|
|
394
|
+
ry /= rl;
|
|
395
|
+
rz /= rl;
|
|
396
|
+
const vx = rx * dx + ux * dy;
|
|
397
|
+
const vy = ry * dx + uy * dy;
|
|
398
|
+
const vz = rz * dx + uz * dy;
|
|
399
|
+
fvMove(c.center, t, vx, vy, vz);
|
|
400
|
+
let radius = Math.exp(c.computedRadius[0]);
|
|
401
|
+
radius = Math.max(1e-4, radius + dz);
|
|
402
|
+
fvSet(c.radius, t, Math.log(radius));
|
|
403
|
+
}
|
|
404
|
+
// ---------------------------------------------------------------------------
|
|
405
|
+
// Inlined from matrix-camera-controller/matrix.js
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
const matrixTVec = [0, 0, 0];
|
|
408
|
+
function matrixRecalcMatrix(c, t) {
|
|
409
|
+
const time = c._time;
|
|
410
|
+
const tidx = bsearch.le(time, t);
|
|
411
|
+
const mat = c.computedMatrix;
|
|
412
|
+
if (tidx < 0)
|
|
413
|
+
return;
|
|
414
|
+
const comps = c._components;
|
|
415
|
+
if (tidx === time.length - 1) {
|
|
416
|
+
let ptr = 16 * tidx;
|
|
417
|
+
for (let i = 0; i < 16; ++i)
|
|
418
|
+
mat[i] = comps[ptr++];
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
const dt = time[tidx + 1] - time[tidx];
|
|
422
|
+
let ptr = 16 * tidx;
|
|
423
|
+
const prev = c.prevMatrix;
|
|
424
|
+
let allEqual = true;
|
|
425
|
+
for (let i = 0; i < 16; ++i)
|
|
426
|
+
prev[i] = comps[ptr++];
|
|
427
|
+
const next = c.nextMatrix;
|
|
428
|
+
for (let i = 0; i < 16; ++i) {
|
|
429
|
+
next[i] = comps[ptr++];
|
|
430
|
+
allEqual = allEqual && prev[i] === next[i];
|
|
431
|
+
}
|
|
432
|
+
if (dt < 1e-6 || allEqual) {
|
|
433
|
+
for (let i = 0; i < 16; ++i)
|
|
434
|
+
mat[i] = prev[i];
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
mat4Interpolate(mat, prev, next, (t - time[tidx]) / dt);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
const up = c.computedUp;
|
|
441
|
+
up[0] = mat[1];
|
|
442
|
+
up[1] = mat[5];
|
|
443
|
+
up[2] = mat[9];
|
|
444
|
+
vec3Normalize(up, up);
|
|
445
|
+
const imat = c.computedInverse;
|
|
446
|
+
mat4Invert(imat, mat);
|
|
447
|
+
const eye = c.computedEye;
|
|
448
|
+
const w = imat[15];
|
|
449
|
+
eye[0] = imat[12] / w;
|
|
450
|
+
eye[1] = imat[13] / w;
|
|
451
|
+
eye[2] = imat[14] / w;
|
|
452
|
+
const center = c.computedCenter;
|
|
453
|
+
const radius = Math.exp(c.computedRadius[0]);
|
|
454
|
+
for (let i = 0; i < 3; ++i)
|
|
455
|
+
center[i] = eye[i] - mat[2 + 4 * i] * radius;
|
|
456
|
+
}
|
|
457
|
+
function matrixSetMatrix(c, t, mat) {
|
|
458
|
+
// Inlined: proto.setMatrix
|
|
459
|
+
if (t < c._time[c._time.length - 1])
|
|
460
|
+
return;
|
|
461
|
+
c._time.push(t);
|
|
462
|
+
for (let i = 0; i < 16; ++i)
|
|
463
|
+
c._components.push(mat[i]);
|
|
464
|
+
}
|
|
465
|
+
function matrixRotate(c, t, yaw, pitch, roll) {
|
|
466
|
+
matrixRecalcMatrix(c, t);
|
|
467
|
+
const mat = c.computedInverse;
|
|
468
|
+
if (yaw)
|
|
469
|
+
mat4RotateY(mat, mat, yaw);
|
|
470
|
+
if (pitch)
|
|
471
|
+
mat4RotateX(mat, mat, pitch);
|
|
472
|
+
if (roll)
|
|
473
|
+
mat4RotateZ(mat, mat, roll);
|
|
474
|
+
matrixSetMatrix(c, t, mat4Invert(c.computedMatrix, mat));
|
|
475
|
+
}
|
|
476
|
+
function matrixPan(c, t, dx, dy, dz) {
|
|
477
|
+
matrixTVec[0] = -(dx || 0.0);
|
|
478
|
+
matrixTVec[1] = -(dy || 0.0);
|
|
479
|
+
matrixTVec[2] = -(dz || 0.0);
|
|
480
|
+
matrixRecalcMatrix(c, t);
|
|
481
|
+
const mat = c.computedInverse;
|
|
482
|
+
mat4Translate(mat, mat, matrixTVec);
|
|
483
|
+
matrixSetMatrix(c, t, mat4Invert(mat, mat));
|
|
484
|
+
}
|
|
485
|
+
// ---------------------------------------------------------------------------
|
|
486
|
+
// Inlined: 3d-view/view.js#rotate, #pan — dispatcher fan-out.
|
|
487
|
+
// _controllerList order matches the keys passed to ViewController:
|
|
488
|
+
// [turntable, orbit, matrix]. The dispatch loop calls the same method on
|
|
489
|
+
// each so all three stay in sync.
|
|
490
|
+
// ---------------------------------------------------------------------------
|
|
491
|
+
function viewRotate(t, a1, a2, a3) {
|
|
492
|
+
turntableRotate(view._controllerList[0], t, a1, a2, a3);
|
|
493
|
+
orbitRotate(view._controllerList[1], t, a1, a2, a3);
|
|
494
|
+
matrixRotate(view._controllerList[2], t, a1, a2, a3);
|
|
495
|
+
}
|
|
496
|
+
function viewPan(t, a1, a2, a3) {
|
|
497
|
+
turntablePan(view._controllerList[0], t, a1, a2, a3);
|
|
498
|
+
orbitPan(view._controllerList[1], t, a1, a2, a3);
|
|
499
|
+
matrixPan(view._controllerList[2], t, a1, a2, a3);
|
|
500
|
+
}
|
|
501
|
+
// ===========================================================================
|
|
502
|
+
// Event handlers
|
|
503
|
+
// ===========================================================================
|
|
504
|
+
function onMouseMove(event) {
|
|
505
|
+
// ---- Inlined: mouse-change/mouse-listen.js#handleMouseMove -----------
|
|
506
|
+
// Inlined: mouse-event/mouse.js#buttons(ev) — modern path returns ev.buttons.
|
|
507
|
+
const mouseEventButtons = ("buttons" in event)
|
|
508
|
+
? event.buttons
|
|
509
|
+
: (("which" in event)
|
|
510
|
+
? (event.which === 2 ? 4
|
|
511
|
+
: event.which === 3 ? 2
|
|
512
|
+
: event.which > 0 ? (1 << (event.which - 1))
|
|
513
|
+
: 0)
|
|
514
|
+
: (("button" in event)
|
|
515
|
+
? (event.button === 1 ? 4
|
|
516
|
+
: event.button === 2 ? 2
|
|
517
|
+
: event.button >= 0 ? (1 << event.button)
|
|
518
|
+
: 0)
|
|
519
|
+
: 0));
|
|
520
|
+
const dispatchButtons = mouseEventButtons === 0 ? 0 : buttonState;
|
|
521
|
+
// ---- Inlined: handleEvent(dispatchButtons, event) --------------------
|
|
522
|
+
// Inlined: mouse-event/mouse.js#x, #y
|
|
523
|
+
let nextX, nextY;
|
|
524
|
+
if ("offsetX" in event) {
|
|
525
|
+
nextX = event.offsetX;
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
const target = event.target || event.srcElement || window;
|
|
529
|
+
nextX = event.clientX - target.getBoundingClientRect().left;
|
|
530
|
+
}
|
|
531
|
+
if ("offsetY" in event) {
|
|
532
|
+
nextY = event.offsetY;
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
const target = event.target || event.srcElement || window;
|
|
536
|
+
nextY = event.clientY - target.getBoundingClientRect().top;
|
|
537
|
+
}
|
|
538
|
+
let nextButtons = dispatchButtons;
|
|
539
|
+
if ("buttons" in event)
|
|
540
|
+
nextButtons = event.buttons | 0;
|
|
541
|
+
// Inlined: updateMods(ev)
|
|
542
|
+
let modsChanged = false;
|
|
543
|
+
if ("altKey" in event) {
|
|
544
|
+
modsChanged = modsChanged || event.altKey !== mcMods.alt;
|
|
545
|
+
mcMods.alt = !!event.altKey;
|
|
546
|
+
}
|
|
547
|
+
if ("shiftKey" in event) {
|
|
548
|
+
modsChanged = modsChanged || event.shiftKey !== mcMods.shift;
|
|
549
|
+
mcMods.shift = !!event.shiftKey;
|
|
550
|
+
}
|
|
551
|
+
if ("ctrlKey" in event) {
|
|
552
|
+
modsChanged = modsChanged || event.ctrlKey !== mcMods.control;
|
|
553
|
+
mcMods.control = !!event.ctrlKey;
|
|
554
|
+
}
|
|
555
|
+
if ("metaKey" in event) {
|
|
556
|
+
modsChanged = modsChanged || event.metaKey !== mcMods.meta;
|
|
557
|
+
mcMods.meta = !!event.metaKey;
|
|
558
|
+
}
|
|
559
|
+
if (!(nextButtons !== buttonState || nextX !== mcX || nextY !== mcY || modsChanged)) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
buttonState = nextButtons | 0;
|
|
563
|
+
mcX = nextX || 0;
|
|
564
|
+
mcY = nextY || 0;
|
|
565
|
+
const buttons = buttonState;
|
|
566
|
+
const x = mcX;
|
|
567
|
+
const y = mcY;
|
|
568
|
+
const mods = mcMods;
|
|
569
|
+
// ---- Inlined: handleInteraction(buttons, x, y, mods) -----------------
|
|
570
|
+
const scale = 1.0 / element.clientHeight;
|
|
571
|
+
const dx = scale * (x - lastX);
|
|
572
|
+
const dy = scale * (y - lastY);
|
|
573
|
+
const flipX = camera.flipX ? 1 : -1;
|
|
574
|
+
const flipY = camera.flipY ? 1 : -1;
|
|
575
|
+
const drot = Math.PI * camera.rotateSpeed;
|
|
576
|
+
// Inlined: now()
|
|
577
|
+
const t = performance.now();
|
|
578
|
+
if (buttons & 1) {
|
|
579
|
+
if (mods.shift) {
|
|
580
|
+
// Inlined: view.rotate(t, 0, 0, -dx * drot)
|
|
581
|
+
viewRotate(t, 0, 0, -dx * drot);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
// Inlined: view.rotate(t, flipX*drot*dx, -flipY*drot*dy, 0)
|
|
585
|
+
viewRotate(t, flipX * drot * dx, -flipY * drot * dy, 0);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
else if (buttons & 2) {
|
|
589
|
+
// Inlined: view.pan(t, -translateSpeed*dx*distance, translateSpeed*dy*distance, 0)
|
|
590
|
+
viewPan(t, -camera.translateSpeed * dx * distance, camera.translateSpeed * dy * distance, 0);
|
|
591
|
+
}
|
|
592
|
+
else if (buttons & 4) {
|
|
593
|
+
// Inlined: view.pan(t, 0, 0, distance * (Math.exp(kzoom) - 1))
|
|
594
|
+
const kzoom = camera.zoomSpeed * dy / window.innerHeight * (t - view.lastT()) * 50.0;
|
|
595
|
+
viewPan(t, 0, 0, distance * (Math.exp(kzoom) - 1));
|
|
596
|
+
}
|
|
597
|
+
lastX = x;
|
|
598
|
+
lastY = y;
|
|
599
|
+
lastMods = mods;
|
|
600
|
+
}
|
|
601
|
+
function onWheel(event) {
|
|
602
|
+
// ---- Inlined: mouse-wheel/wheel.js#listener --------------------------
|
|
603
|
+
// The third arg `noScroll = true` was passed in 3d-view-controls.js, so
|
|
604
|
+
// the listener always calls preventDefault().
|
|
605
|
+
event.preventDefault();
|
|
606
|
+
let dx = event.deltaX || 0;
|
|
607
|
+
let dy = event.deltaY || 0;
|
|
608
|
+
let dz = event.deltaZ || 0;
|
|
609
|
+
let wheelScale = 1;
|
|
610
|
+
switch (event.deltaMode) {
|
|
611
|
+
case 1:
|
|
612
|
+
wheelScale = lineHeight;
|
|
613
|
+
break; // DOM_DELTA_LINE
|
|
614
|
+
case 2:
|
|
615
|
+
wheelScale = window.innerHeight;
|
|
616
|
+
break; // DOM_DELTA_PAGE
|
|
617
|
+
}
|
|
618
|
+
dx *= wheelScale;
|
|
619
|
+
dy *= wheelScale;
|
|
620
|
+
dz *= wheelScale;
|
|
621
|
+
if (!(dx || dy || dz))
|
|
622
|
+
return;
|
|
623
|
+
// ---- Inlined: wheel callback from 3d-view-controls.js ----------------
|
|
624
|
+
const flipX = camera.flipX ? 1 : -1;
|
|
625
|
+
const flipY = camera.flipY ? 1 : -1;
|
|
626
|
+
// Inlined: now()
|
|
627
|
+
const t = performance.now();
|
|
628
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
629
|
+
// Inlined: view.rotate(t, 0, 0, -dx*flipX*PI*rotateSpeed / window.innerWidth)
|
|
630
|
+
viewRotate(t, 0, 0, -dx * flipX * Math.PI * camera.rotateSpeed / window.innerWidth);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
// Inlined: view.pan(t, 0, 0, distance * (Math.exp(kzoom) - 1))
|
|
634
|
+
const kzoom = camera.zoomSpeed * flipY * dy / window.innerHeight * (t - view.lastT()) / 100.0;
|
|
635
|
+
viewPan(t, 0, 0, distance * (Math.exp(kzoom) - 1));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unrolled-dom-2d-camera.d.ts","sourceRoot":"","sources":["../src/unrolled-dom-2d-camera.js"],"names":[],"mappings":""}
|