@rednaxela101/cubing 0.63.8 → 0.63.10
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 +5 -5
- package/dist/bin/chunks/{chunk-EWR23OA4.js → chunk-3WUR6UXA.js} +2 -2
- package/dist/bin/order.js +1 -1
- package/dist/bin/puzzle-geometry-bin.js +1 -1
- package/dist/bin/scramble.js +1 -1
- package/dist/bin/svg.js +1 -1
- package/dist/lib/cubing/alg/index.d.ts +1 -1
- package/dist/lib/cubing/bluetooth/index.d.ts +2 -2
- package/dist/lib/cubing/chunks/{chunk-B2YKAP2I.js → chunk-IOHGEWB2.js} +2 -2
- package/dist/lib/cubing/chunks/{twisty-dynamic-3d-SLKSUJTE.js → twisty-dynamic-3d-3MGVD3TG.js} +928 -334
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-3MGVD3TG.js.map +7 -0
- package/dist/lib/cubing/{index-ylnTp4i5.d.ts → index-0OM9yjf0.d.ts} +1 -1
- package/dist/lib/cubing/{index-FT5_Vsnm.d.ts → index-B_TS5TTk.d.ts} +13 -0
- package/dist/lib/cubing/kpuzzle/index.d.ts +1 -1
- package/dist/lib/cubing/notation/index.d.ts +1 -1
- package/dist/lib/cubing/{outside-D3tRtsxV.d.ts → outside-BUsE7O5Q.d.ts} +1 -1
- package/dist/lib/cubing/protocol/index.d.ts +1 -1
- package/dist/lib/cubing/puzzle-geometry/index.d.ts +1 -1
- package/dist/lib/cubing/puzzles/index.d.ts +1 -1
- package/dist/lib/cubing/scramble/index.d.ts +1 -1
- package/dist/lib/cubing/search/index.d.ts +1 -1
- package/dist/lib/cubing/stream/index.d.ts +1 -1
- package/dist/lib/cubing/twisty/index.d.ts +1 -1
- package/dist/lib/cubing/twisty/index.js +31 -2
- package/dist/lib/cubing/twisty/index.js.map +2 -2
- package/package.json +1 -1
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-SLKSUJTE.js.map +0 -7
- /package/dist/bin/chunks/{chunk-EWR23OA4.js.map → chunk-3WUR6UXA.js.map} +0 -0
- /package/dist/lib/cubing/chunks/{chunk-B2YKAP2I.js.map → chunk-IOHGEWB2.js.map} +0 -0
package/dist/lib/cubing/chunks/{twisty-dynamic-3d-SLKSUJTE.js → twisty-dynamic-3d-3MGVD3TG.js}
RENAMED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
bulk3DCode,
|
|
4
4
|
haveStartedSharingRenderers,
|
|
5
5
|
hintFaceletStyles
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IOHGEWB2.js";
|
|
7
7
|
import "./chunk-3ODTF4HE.js";
|
|
8
8
|
import {
|
|
9
9
|
cube3x3x3,
|
|
@@ -15,20 +15,20 @@ import {
|
|
|
15
15
|
} from "./chunk-XPDJUSZ7.js";
|
|
16
16
|
|
|
17
17
|
// src/cubing/twisty/views/3D/puzzles/Cube3D.ts
|
|
18
|
-
import { BackSide, DoubleSide, FrontSide } from "three/src/constants.js";
|
|
19
|
-
import { BufferAttribute as
|
|
20
|
-
import { BufferGeometry as
|
|
18
|
+
import { BackSide, DoubleSide, FrontSide as FrontSide2 } from "three/src/constants.js";
|
|
19
|
+
import { BufferAttribute as BufferAttribute3 } from "three/src/core/BufferAttribute.js";
|
|
20
|
+
import { BufferGeometry as BufferGeometry3 } from "three/src/core/BufferGeometry.js";
|
|
21
21
|
import { Object3D } from "three/src/core/Object3D.js";
|
|
22
22
|
import { BoxGeometry } from "three/src/geometries/BoxGeometry.js";
|
|
23
23
|
import { TextureLoader } from "three/src/loaders/TextureLoader.js";
|
|
24
|
-
import { MeshBasicMaterial } from "three/src/materials/MeshBasicMaterial.js";
|
|
24
|
+
import { MeshBasicMaterial as MeshBasicMaterial3 } from "three/src/materials/MeshBasicMaterial.js";
|
|
25
25
|
import { Color as Color2 } from "three/src/math/Color.js";
|
|
26
26
|
import { Matrix4 } from "three/src/math/Matrix4.js";
|
|
27
27
|
import { Quaternion } from "three/src/math/Quaternion.js";
|
|
28
28
|
import { Vector2 } from "three/src/math/Vector2.js";
|
|
29
|
-
import { Vector3 as
|
|
29
|
+
import { Vector3 as Vector34 } from "three/src/math/Vector3.js";
|
|
30
30
|
import { Group } from "three/src/objects/Group.js";
|
|
31
|
-
import { Mesh } from "three/src/objects/Mesh.js";
|
|
31
|
+
import { Mesh as Mesh2 } from "three/src/objects/Mesh.js";
|
|
32
32
|
|
|
33
33
|
// src/cubing/twisty/controllers/easing.ts
|
|
34
34
|
function smootherStep(x) {
|
|
@@ -87,7 +87,6 @@ function beveledCubieGeometry(faceNormals, outerFaceIndices, halfSize, outerAxis
|
|
|
87
87
|
}
|
|
88
88
|
const gridSize = samples.length;
|
|
89
89
|
const positions = [];
|
|
90
|
-
const normals = [];
|
|
91
90
|
const indices = [];
|
|
92
91
|
const geometry = new BufferGeometry();
|
|
93
92
|
const point = new Vector3();
|
|
@@ -140,9 +139,6 @@ function beveledCubieGeometry(faceNormals, outerFaceIndices, halfSize, outerAxis
|
|
|
140
139
|
core.y + offset.y * radii.y,
|
|
141
140
|
core.z + offset.z * radii.z
|
|
142
141
|
);
|
|
143
|
-
normals.push(
|
|
144
|
-
...offset.set(offset.x / radii.x, offset.y / radii.y, offset.z / radii.z).normalize().toArray()
|
|
145
|
-
);
|
|
146
142
|
}
|
|
147
143
|
}
|
|
148
144
|
const indexStart = indices.length;
|
|
@@ -159,18 +155,12 @@ function beveledCubieGeometry(faceNormals, outerFaceIndices, halfSize, outerAxis
|
|
|
159
155
|
"position",
|
|
160
156
|
new BufferAttribute(new Float32Array(positions), 3)
|
|
161
157
|
);
|
|
162
|
-
geometry.setAttribute(
|
|
163
|
-
"normal",
|
|
164
|
-
new BufferAttribute(new Float32Array(normals), 3)
|
|
165
|
-
);
|
|
166
158
|
geometry.setIndex(indices);
|
|
167
159
|
return geometry;
|
|
168
160
|
}
|
|
169
161
|
|
|
170
162
|
// src/cubing/twisty/views/3D/puzzles/CubieStyle.ts
|
|
171
|
-
import {
|
|
172
|
-
import { DirectionalLight } from "three/src/lights/DirectionalLight.js";
|
|
173
|
-
import { MeshPhongMaterial } from "three/src/materials/MeshPhongMaterial.js";
|
|
163
|
+
import { MeshBasicMaterial } from "three/src/materials/MeshBasicMaterial.js";
|
|
174
164
|
import { Color } from "three/src/math/Color.js";
|
|
175
165
|
import { Euler } from "three/src/math/Euler.js";
|
|
176
166
|
import { Vector3 as Vector32 } from "three/src/math/Vector3.js";
|
|
@@ -268,18 +258,14 @@ var cubieBodyDimensions = {
|
|
|
268
258
|
* a thin line of the puzzle's interior showing between them.
|
|
269
259
|
*/
|
|
270
260
|
pieceScale: 0.95,
|
|
271
|
-
roundingSegments:
|
|
261
|
+
roundingSegments: 3
|
|
272
262
|
};
|
|
273
263
|
function cubieBodyHalfExtent(layers) {
|
|
274
264
|
return layers / 2 - 0.5 + cubieBodyDimensions.halfWidth * cubieBodyDimensions.pieceScale;
|
|
275
265
|
}
|
|
276
|
-
var BODY_SHININESS = 30;
|
|
277
|
-
var BODY_SPECULAR = 657930;
|
|
278
266
|
function newBodyMaterial(color) {
|
|
279
|
-
return new
|
|
280
|
-
color: typeof color === "number" ? new Color(color).convertLinearToSRGB() : color
|
|
281
|
-
shininess: BODY_SHININESS,
|
|
282
|
-
specular: new Color(BODY_SPECULAR).convertLinearToSRGB()
|
|
267
|
+
return new MeshBasicMaterial({
|
|
268
|
+
color: typeof color === "number" ? new Color(color).convertLinearToSRGB() : color
|
|
283
269
|
});
|
|
284
270
|
}
|
|
285
271
|
function newVertexColorBodyMaterial() {
|
|
@@ -301,51 +287,241 @@ var hintMaskStyles = {
|
|
|
301
287
|
experimentalOriented2: { color: 16775545, opacity: 0.5 },
|
|
302
288
|
mystery: { color: 15911883, opacity: 0.5 }
|
|
303
289
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
290
|
+
|
|
291
|
+
// src/cubing/twisty/views/3D/puzzles/PuzzleLogo.ts
|
|
292
|
+
import { FrontSide } from "three/src/constants.js";
|
|
293
|
+
import { BufferAttribute as BufferAttribute2 } from "three/src/core/BufferAttribute.js";
|
|
294
|
+
import { BufferGeometry as BufferGeometry2 } from "three/src/core/BufferGeometry.js";
|
|
295
|
+
import { MeshBasicMaterial as MeshBasicMaterial2 } from "three/src/materials/MeshBasicMaterial.js";
|
|
296
|
+
import { Vector3 as Vector33 } from "three/src/math/Vector3.js";
|
|
297
|
+
import { Mesh } from "three/src/objects/Mesh.js";
|
|
298
|
+
var LOGO_FIT = 0.8;
|
|
299
|
+
var EPSILON = 1e-9;
|
|
300
|
+
function logoSurface(polygon, normal2, elevation) {
|
|
301
|
+
if (polygon.length < 3) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
const center = new Vector33();
|
|
305
|
+
for (const vertex of polygon) {
|
|
306
|
+
center.addScaledVector(vertex, 1 / polygon.length);
|
|
307
|
+
}
|
|
308
|
+
const u = new Vector33().subVectors(polygon[1], polygon[0]).addScaledVector(
|
|
309
|
+
normal2,
|
|
310
|
+
-new Vector33().subVectors(polygon[1], polygon[0]).dot(normal2)
|
|
311
|
+
);
|
|
312
|
+
if (u.lengthSq() < EPSILON) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
u.normalize();
|
|
316
|
+
const v = new Vector33().crossVectors(normal2, u).normalize();
|
|
317
|
+
let half = Number.POSITIVE_INFINITY;
|
|
318
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
319
|
+
const edge = new Vector33().subVectors(
|
|
320
|
+
polygon[(i + 1) % polygon.length],
|
|
321
|
+
polygon[i]
|
|
322
|
+
);
|
|
323
|
+
const outward = new Vector33().crossVectors(edge, normal2);
|
|
324
|
+
if (outward.lengthSq() < EPSILON) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
outward.normalize();
|
|
328
|
+
const distance = Math.abs(
|
|
329
|
+
new Vector33().subVectors(polygon[i], center).dot(outward)
|
|
330
|
+
);
|
|
331
|
+
const reach = Math.abs(outward.dot(u)) + Math.abs(outward.dot(v));
|
|
332
|
+
if (reach > EPSILON) {
|
|
333
|
+
half = Math.min(half, distance / reach);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (!Number.isFinite(half) || half <= 0) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
half *= LOGO_FIT;
|
|
340
|
+
return {
|
|
341
|
+
center: center.addScaledVector(normal2, elevation),
|
|
342
|
+
u: u.multiplyScalar(half),
|
|
343
|
+
v: v.multiplyScalar(half)
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function rectangleLogoSurface(center, u, v) {
|
|
347
|
+
const half = LOGO_FIT * Math.min(u.length(), v.length());
|
|
348
|
+
return {
|
|
349
|
+
center,
|
|
350
|
+
u: u.clone().setLength(half),
|
|
351
|
+
v: v.clone().setLength(half)
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function surfaceMatrix(surface, into) {
|
|
355
|
+
return into.makeBasis(
|
|
356
|
+
surface.u,
|
|
357
|
+
surface.v,
|
|
358
|
+
new Vector33().crossVectors(surface.u, surface.v).normalize()
|
|
359
|
+
).setPosition(surface.center);
|
|
360
|
+
}
|
|
361
|
+
var cachedLogoGeometry;
|
|
362
|
+
function logoGeometry() {
|
|
363
|
+
if (cachedLogoGeometry) {
|
|
364
|
+
return cachedLogoGeometry;
|
|
365
|
+
}
|
|
366
|
+
const geometry = new BufferGeometry2();
|
|
367
|
+
geometry.setAttribute(
|
|
368
|
+
"position",
|
|
369
|
+
new BufferAttribute2(
|
|
370
|
+
// biome-ignore format: one vertex per line is less readable than one triangle per line.
|
|
371
|
+
new Float32Array([
|
|
372
|
+
-1,
|
|
373
|
+
-1,
|
|
374
|
+
0,
|
|
375
|
+
1,
|
|
376
|
+
-1,
|
|
377
|
+
0,
|
|
378
|
+
1,
|
|
379
|
+
1,
|
|
380
|
+
0,
|
|
381
|
+
-1,
|
|
382
|
+
-1,
|
|
383
|
+
0,
|
|
384
|
+
1,
|
|
385
|
+
1,
|
|
386
|
+
0,
|
|
387
|
+
-1,
|
|
388
|
+
1,
|
|
389
|
+
0
|
|
390
|
+
]),
|
|
391
|
+
3
|
|
392
|
+
)
|
|
393
|
+
);
|
|
394
|
+
geometry.setAttribute(
|
|
395
|
+
"uv",
|
|
396
|
+
// biome-ignore format: see above.
|
|
397
|
+
new BufferAttribute2(new Float32Array([
|
|
398
|
+
0,
|
|
399
|
+
0,
|
|
400
|
+
1,
|
|
401
|
+
0,
|
|
402
|
+
1,
|
|
403
|
+
1,
|
|
404
|
+
0,
|
|
405
|
+
0,
|
|
406
|
+
1,
|
|
407
|
+
1,
|
|
408
|
+
0,
|
|
409
|
+
1
|
|
410
|
+
]), 2)
|
|
411
|
+
);
|
|
412
|
+
cachedLogoGeometry = geometry;
|
|
413
|
+
return geometry;
|
|
414
|
+
}
|
|
415
|
+
function newLogoMesh(texture) {
|
|
416
|
+
const mesh = new Mesh(
|
|
417
|
+
logoGeometry(),
|
|
418
|
+
new MeshBasicMaterial2({
|
|
419
|
+
map: texture,
|
|
420
|
+
side: FrontSide,
|
|
421
|
+
transparent: true,
|
|
422
|
+
// The logo floats just above the plastic, so it never has to compete with
|
|
423
|
+
// it for depth, and writing depth would let its transparent corners
|
|
424
|
+
// punch a hole in anything drawn after it.
|
|
425
|
+
depthWrite: false
|
|
426
|
+
})
|
|
427
|
+
);
|
|
428
|
+
mesh.matrixAutoUpdate = false;
|
|
429
|
+
mesh.renderOrder = 1;
|
|
430
|
+
return mesh;
|
|
431
|
+
}
|
|
432
|
+
var logoSpots = {
|
|
433
|
+
// Every piece of a 2×2×2 is a corner, so this is just "a piece of the white
|
|
434
|
+
// face".
|
|
435
|
+
"2x2x2": { face: "U", corner: true, toward: [1, 1, 1] },
|
|
436
|
+
// `Cube3D` draws the 3×3×3 by default and places its own logo; this is for
|
|
437
|
+
// `visualization="PG3D"`.
|
|
438
|
+
"3x3x3": { face: "U" },
|
|
439
|
+
"4x4x4": { face: "U", corner: true, toward: [1, 1, 1] },
|
|
440
|
+
"5x5x5": { face: "U", corner: true, toward: [1, 1, 1] },
|
|
441
|
+
"6x6x6": { face: "U", corner: true, toward: [1, 1, 1] },
|
|
442
|
+
"7x7x7": { face: "U", corner: true, toward: [1, 1, 1] },
|
|
443
|
+
megaminx: { face: "U" },
|
|
444
|
+
// A pyraminx has no center piece: the middle of a face is an edge's facelet.
|
|
445
|
+
pyraminx: { face: "D" },
|
|
446
|
+
skewb: { face: "U" }
|
|
447
|
+
// No logo on the FTO or the clock.
|
|
448
|
+
};
|
|
449
|
+
function centroid(coords) {
|
|
450
|
+
const center = new Vector33();
|
|
451
|
+
const vertices = coords.length / 3;
|
|
452
|
+
for (let i = 0; i < coords.length; i += 3) {
|
|
453
|
+
center.x += coords[i] / vertices;
|
|
454
|
+
center.y += coords[i + 1] / vertices;
|
|
455
|
+
center.z += coords[i + 2] / vertices;
|
|
456
|
+
}
|
|
457
|
+
return center;
|
|
458
|
+
}
|
|
459
|
+
function logoFaceletAddress(puzzleID, stickerDat) {
|
|
460
|
+
const spot = logoSpots[puzzleID];
|
|
461
|
+
if (!spot) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
const faceIdx = stickerDat.faces.findIndex((face2) => face2.name === spot.face);
|
|
465
|
+
if (faceIdx === -1) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
const faceCenter = centroid(stickerDat.faces[faceIdx].coords);
|
|
469
|
+
const faceletCounts = /* @__PURE__ */ new Map();
|
|
470
|
+
for (const sticker of stickerDat.stickers) {
|
|
471
|
+
if (sticker.isDup) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const key = `${sticker.orbit}/${sticker.ord}`;
|
|
475
|
+
faceletCounts.set(key, (faceletCounts.get(key) ?? 0) + 1);
|
|
476
|
+
}
|
|
477
|
+
const toward = spot.toward ? new Vector33(...spot.toward) : null;
|
|
478
|
+
let best = null;
|
|
479
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
480
|
+
for (const sticker of stickerDat.stickers) {
|
|
481
|
+
if (sticker.isDup || sticker.face !== faceIdx) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (spot.corner && faceletCounts.get(`${sticker.orbit}/${sticker.ord}`) !== 3) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
const center = centroid(sticker.coords);
|
|
488
|
+
const score = toward ? center.dot(toward) : -center.distanceTo(faceCenter);
|
|
489
|
+
if (score > bestScore) {
|
|
490
|
+
bestScore = score;
|
|
491
|
+
best = { orbit: sticker.orbit, ord: sticker.ord, ori: sticker.ori };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return best;
|
|
319
495
|
}
|
|
320
496
|
|
|
321
497
|
// src/cubing/twisty/views/3D/puzzles/Cube3D.ts
|
|
322
498
|
var svgLoader = new TextureLoader();
|
|
323
499
|
function newHintMaterial(style) {
|
|
324
|
-
return new
|
|
500
|
+
return new MeshBasicMaterial3({
|
|
325
501
|
color: new Color2(style.color).convertLinearToSRGB(),
|
|
326
502
|
side: BackSide,
|
|
327
503
|
transparent: true,
|
|
328
504
|
opacity: style.opacity
|
|
329
505
|
});
|
|
330
506
|
}
|
|
331
|
-
var ignoredMaterial = new
|
|
507
|
+
var ignoredMaterial = new MeshBasicMaterial3({
|
|
332
508
|
color: new Color2(bodyMaskColors.ignored).convertLinearToSRGB()
|
|
333
509
|
});
|
|
334
510
|
var ignoredMaterialHint = newHintMaterial(hintMaskStyles.ignored);
|
|
335
|
-
var invisibleMaterial = new
|
|
511
|
+
var invisibleMaterial = new MeshBasicMaterial3({
|
|
336
512
|
visible: false
|
|
337
513
|
});
|
|
338
|
-
var orientedMaterial = new
|
|
514
|
+
var orientedMaterial = new MeshBasicMaterial3({
|
|
339
515
|
color: bodyMaskColors.oriented
|
|
340
516
|
});
|
|
341
517
|
var orientedMaterialHint = newHintMaterial(hintMaskStyles.oriented);
|
|
342
|
-
var experimentalOriented2Material = new
|
|
518
|
+
var experimentalOriented2Material = new MeshBasicMaterial3({
|
|
343
519
|
color: bodyMaskColors.experimentalOriented2
|
|
344
520
|
});
|
|
345
521
|
var experimentalOriented2MaterialHint = newHintMaterial(
|
|
346
522
|
hintMaskStyles.experimentalOriented2
|
|
347
523
|
);
|
|
348
|
-
var mysteryMaterial = new
|
|
524
|
+
var mysteryMaterial = new MeshBasicMaterial3({
|
|
349
525
|
color: bodyMaskColors.mystery
|
|
350
526
|
});
|
|
351
527
|
var mysterMaterialHint = newHintMaterial(hintMaskStyles.mystery);
|
|
@@ -369,14 +545,14 @@ var AxisInfo = class {
|
|
|
369
545
|
const colorLinearSRGB = new Color2(color).convertLinearToSRGB();
|
|
370
546
|
const dimColorLinearSRGB = new Color2(dimColor).convertLinearToSRGB();
|
|
371
547
|
this.stickerMaterial = {
|
|
372
|
-
regular: new
|
|
548
|
+
regular: new MeshBasicMaterial3({
|
|
373
549
|
color: colorLinearSRGB,
|
|
374
|
-
side:
|
|
550
|
+
side: FrontSide2
|
|
375
551
|
// TODO: set to `DoubleSide` when hint facelets are disabled.
|
|
376
552
|
}),
|
|
377
|
-
dim: new
|
|
553
|
+
dim: new MeshBasicMaterial3({
|
|
378
554
|
color: dimColorLinearSRGB,
|
|
379
|
-
side:
|
|
555
|
+
side: FrontSide2
|
|
380
556
|
// TODO: set to `DoubleSide` when hint facelets are disabled.
|
|
381
557
|
}),
|
|
382
558
|
oriented: orientedMaterial,
|
|
@@ -467,6 +643,8 @@ var cubieDimensions = {
|
|
|
467
643
|
*/
|
|
468
644
|
bodyVertexCut: 0.45
|
|
469
645
|
};
|
|
646
|
+
var LOGO_PIECE = { orbit: "CENTERS", ord: 0, faceletIdx: 0 };
|
|
647
|
+
var LOGO_ELEVATION = 0.01;
|
|
470
648
|
var EXPERIMENTAL_PICTURE_CUBE_HINT_ELEVATION = 2;
|
|
471
649
|
var cube3DOptionsDefaults = {
|
|
472
650
|
showMainStickers: true,
|
|
@@ -487,12 +665,12 @@ function getFaceletScale(options) {
|
|
|
487
665
|
}
|
|
488
666
|
return options.faceletScale;
|
|
489
667
|
}
|
|
490
|
-
var blackMesh = new
|
|
668
|
+
var blackMesh = new MeshBasicMaterial3({
|
|
491
669
|
color: 0,
|
|
492
670
|
opacity: 1,
|
|
493
671
|
transparent: true
|
|
494
672
|
});
|
|
495
|
-
var blackTranslucentMesh = new
|
|
673
|
+
var blackTranslucentMesh = new MeshBasicMaterial3({
|
|
496
674
|
color: 0,
|
|
497
675
|
opacity: 0.3,
|
|
498
676
|
transparent: true
|
|
@@ -515,18 +693,18 @@ function t(v, t4) {
|
|
|
515
693
|
return new Quaternion().setFromAxisAngle(v, TAU * t4 / 4);
|
|
516
694
|
}
|
|
517
695
|
var r = {
|
|
518
|
-
O: new
|
|
519
|
-
U: new
|
|
520
|
-
L: new
|
|
521
|
-
F: new
|
|
522
|
-
R: new
|
|
523
|
-
B: new
|
|
524
|
-
D: new
|
|
696
|
+
O: new Vector34(0, 0, 0),
|
|
697
|
+
U: new Vector34(0, -1, 0),
|
|
698
|
+
L: new Vector34(1, 0, 0),
|
|
699
|
+
F: new Vector34(0, 0, -1),
|
|
700
|
+
R: new Vector34(-1, 0, 0),
|
|
701
|
+
B: new Vector34(0, 0, 1),
|
|
702
|
+
D: new Vector34(0, 1, 0)
|
|
525
703
|
};
|
|
526
704
|
var firstPiecePosition = {
|
|
527
|
-
EDGES: new
|
|
528
|
-
CORNERS: new
|
|
529
|
-
CENTERS: new
|
|
705
|
+
EDGES: new Vector34(0, 1, 1),
|
|
706
|
+
CORNERS: new Vector34(1, 1, 1),
|
|
707
|
+
CENTERS: new Vector34(0, 1, 0)
|
|
530
708
|
};
|
|
531
709
|
var orientationRotation = {
|
|
532
710
|
EDGES: [0, 1].map(
|
|
@@ -698,11 +876,11 @@ function sharedCubieFoundationGeometry() {
|
|
|
698
876
|
));
|
|
699
877
|
}
|
|
700
878
|
function newStickerGeometry() {
|
|
701
|
-
const r2 = new
|
|
879
|
+
const r2 = new BufferGeometry3();
|
|
702
880
|
const half = 0.5;
|
|
703
881
|
r2.setAttribute(
|
|
704
882
|
"position",
|
|
705
|
-
new
|
|
883
|
+
new BufferAttribute3(
|
|
706
884
|
new Float32Array([
|
|
707
885
|
half,
|
|
708
886
|
half,
|
|
@@ -728,7 +906,7 @@ function newStickerGeometry() {
|
|
|
728
906
|
);
|
|
729
907
|
r2.setAttribute(
|
|
730
908
|
"uv",
|
|
731
|
-
new
|
|
909
|
+
new BufferAttribute3(
|
|
732
910
|
new Float32Array([
|
|
733
911
|
1,
|
|
734
912
|
1,
|
|
@@ -810,9 +988,6 @@ var Cube3D = class extends Object3D {
|
|
|
810
988
|
this.createCubie.bind(this, orbit, orbitFaceletInfo)
|
|
811
989
|
);
|
|
812
990
|
}
|
|
813
|
-
if (this.#stickerless()) {
|
|
814
|
-
addCubieBodyLighting(this);
|
|
815
|
-
}
|
|
816
991
|
const scale = cubeScale(this.#stickerless());
|
|
817
992
|
this.scale.set(scale, scale, scale);
|
|
818
993
|
if (this.options.experimentalStickeringMask) {
|
|
@@ -1010,7 +1185,9 @@ var Cube3D = class extends Object3D {
|
|
|
1010
1185
|
this.setHintFaceletsElevation(hintFaceletsElevation);
|
|
1011
1186
|
}
|
|
1012
1187
|
}
|
|
1188
|
+
#lastPosition = null;
|
|
1013
1189
|
onPositionChange(p) {
|
|
1190
|
+
this.#lastPosition = p;
|
|
1014
1191
|
const reid333 = p.pattern;
|
|
1015
1192
|
for (const orbit in pieceDefs) {
|
|
1016
1193
|
const pieces = pieceDefs[orbit];
|
|
@@ -1040,6 +1217,7 @@ var Cube3D = class extends Object3D {
|
|
|
1040
1217
|
}
|
|
1041
1218
|
}
|
|
1042
1219
|
}
|
|
1220
|
+
this.#placeLogo(p);
|
|
1043
1221
|
this.scheduleRenderCallback();
|
|
1044
1222
|
}
|
|
1045
1223
|
// TODO: Always create (but sometimes hide parts) so we can show them later,
|
|
@@ -1048,7 +1226,7 @@ var Cube3D = class extends Object3D {
|
|
|
1048
1226
|
const cubieFaceletInfo = [];
|
|
1049
1227
|
orbitFacelets.push(cubieFaceletInfo);
|
|
1050
1228
|
const cubie = new Group();
|
|
1051
|
-
const body = this.#stickerless() ? new
|
|
1229
|
+
const body = this.#stickerless() ? new Mesh2(
|
|
1052
1230
|
cubieBodyGeometry(
|
|
1053
1231
|
orbit,
|
|
1054
1232
|
cubieStickerOrder.slice(0, piece.stickerFaces.length)
|
|
@@ -1097,7 +1275,7 @@ var Cube3D = class extends Object3D {
|
|
|
1097
1275
|
axesInfo[piece.stickerFaces[i]],
|
|
1098
1276
|
hint
|
|
1099
1277
|
);
|
|
1100
|
-
mesh.material = new
|
|
1278
|
+
mesh.material = new MeshBasicMaterial3({
|
|
1101
1279
|
map: texture,
|
|
1102
1280
|
side: hint ? BackSide : DoubleSide,
|
|
1103
1281
|
transparent: true
|
|
@@ -1126,7 +1304,7 @@ var Cube3D = class extends Object3D {
|
|
|
1126
1304
|
}
|
|
1127
1305
|
mesh.geometry.setAttribute(
|
|
1128
1306
|
"uv",
|
|
1129
|
-
new
|
|
1307
|
+
new BufferAttribute3(
|
|
1130
1308
|
new Float32Array([
|
|
1131
1309
|
v3.x,
|
|
1132
1310
|
v3.y,
|
|
@@ -1160,14 +1338,14 @@ var Cube3D = class extends Object3D {
|
|
|
1160
1338
|
// TODO: Support creating only the outward-facing parts?
|
|
1161
1339
|
createCubieFoundation() {
|
|
1162
1340
|
const box = sharedCubieFoundationGeometry();
|
|
1163
|
-
return new
|
|
1341
|
+
return new Mesh2(
|
|
1164
1342
|
box,
|
|
1165
1343
|
this.options.experimentalStickeringMask?.specialBehaviour === "picture" ? blackMesh : blackTranslucentMesh
|
|
1166
1344
|
);
|
|
1167
1345
|
}
|
|
1168
1346
|
createSticker(posAxisInfo, materialAxisInfo, isHint) {
|
|
1169
1347
|
const geo = this.options.experimentalStickeringMask?.specialBehaviour === "picture" ? newStickerGeometry() : isHint ? this.#sharedHintStickerGeometry() : sharedStickerGeometry();
|
|
1170
|
-
const stickerMesh = new
|
|
1348
|
+
const stickerMesh = new Mesh2(
|
|
1171
1349
|
geo,
|
|
1172
1350
|
isHint ? materialAxisInfo.hintStickerMaterial.regular : materialAxisInfo.stickerMaterial.regular
|
|
1173
1351
|
);
|
|
@@ -1194,6 +1372,82 @@ var Cube3D = class extends Object3D {
|
|
|
1194
1372
|
stickerMesh.translateZ(elevation - 1);
|
|
1195
1373
|
return stickerMesh;
|
|
1196
1374
|
}
|
|
1375
|
+
#logoMesh = null;
|
|
1376
|
+
/** The logo's placement on its facelet, in the piece's own frame. */
|
|
1377
|
+
#logoSurface = null;
|
|
1378
|
+
#logoPieceMatrix = new Matrix4();
|
|
1379
|
+
/**
|
|
1380
|
+
* Prints a logo on the white center, or takes it off again when passed
|
|
1381
|
+
* `null`.
|
|
1382
|
+
*
|
|
1383
|
+
* The image is stretched onto a square sized to the piece, so its own
|
|
1384
|
+
* proportions don't matter. It rides the piece, so a rotation of the whole
|
|
1385
|
+
* cube carries it to whichever face the white center ends up on.
|
|
1386
|
+
*/
|
|
1387
|
+
experimentalSetLogo(texture) {
|
|
1388
|
+
if (this.#logoMesh) {
|
|
1389
|
+
this.#logoMesh.removeFromParent();
|
|
1390
|
+
this.#logoMesh.material.dispose();
|
|
1391
|
+
this.#logoMesh = null;
|
|
1392
|
+
this.#logoSurface = null;
|
|
1393
|
+
}
|
|
1394
|
+
if (texture) {
|
|
1395
|
+
const normal2 = axesInfo[cubieStickerOrder[LOGO_PIECE.faceletIdx]].vector;
|
|
1396
|
+
const u = new Vector34(normal2.y, normal2.z, normal2.x);
|
|
1397
|
+
const v = new Vector34().crossVectors(normal2, u);
|
|
1398
|
+
const surface = rectangleLogoSurface(
|
|
1399
|
+
normal2.clone().multiplyScalar(this.#faceletDistance() + LOGO_ELEVATION),
|
|
1400
|
+
// Half-axes of the facelet, which is one cubie wide.
|
|
1401
|
+
u.multiplyScalar(0.5),
|
|
1402
|
+
v.multiplyScalar(0.5)
|
|
1403
|
+
);
|
|
1404
|
+
this.#logoMesh = newLogoMesh(texture);
|
|
1405
|
+
this.#logoSurface = surfaceMatrix(surface, new Matrix4());
|
|
1406
|
+
this.add(this.#logoMesh);
|
|
1407
|
+
if (this.#lastPosition) {
|
|
1408
|
+
this.#placeLogo(this.#lastPosition);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
this.scheduleRenderCallback?.();
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Puts the logo where its piece is.
|
|
1415
|
+
*
|
|
1416
|
+
* Almost all of this is the piece's own matrix, but not quite: the 3×3×3's
|
|
1417
|
+
* `KPuzzle` does not track how a center is turned (`orientationMod` is 1),
|
|
1418
|
+
* so a `U` ends in the state it started in as far as the white center is
|
|
1419
|
+
* concerned. Riding that animation would spin the logo through the turn and
|
|
1420
|
+
* snap it back at the end, so a move that leaves the piece in its own slot
|
|
1421
|
+
* leaves the logo alone. A move that carries the piece elsewhere — a cube
|
|
1422
|
+
* rotation — still takes the logo with it.
|
|
1423
|
+
*/
|
|
1424
|
+
#placeLogo(p) {
|
|
1425
|
+
const mesh = this.#logoMesh;
|
|
1426
|
+
if (!mesh || !this.#logoSurface) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
const { orbit, ord } = LOGO_PIECE;
|
|
1430
|
+
const orbitPattern = p.pattern.patternData[orbit];
|
|
1431
|
+
const slot = orbitPattern.pieces.indexOf(ord);
|
|
1432
|
+
if (slot === -1) {
|
|
1433
|
+
mesh.visible = false;
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
mesh.visible = true;
|
|
1437
|
+
const untracked = orbitPattern.orientationMod?.[slot] === 1;
|
|
1438
|
+
const staysPut = untracked && p.movesInProgress.every(
|
|
1439
|
+
(moveProgress) => this.kpuzzle.moveToTransformation(
|
|
1440
|
+
moveProgress.move.modified({ amount: 1 })
|
|
1441
|
+
).transformationData[orbit].permutation[slot] === slot
|
|
1442
|
+
);
|
|
1443
|
+
const pieceMatrix = staysPut ? this.#logoPieceMatrix.copy(pieceDefs[orbit][slot].matrix).multiply(orientationRotation[orbit][orbitPattern.orientation[slot]]) : this.pieces[orbit][ord].matrix;
|
|
1444
|
+
mesh.matrix.multiplyMatrices(pieceMatrix, this.#logoSurface);
|
|
1445
|
+
mesh.matrixWorldNeedsUpdate = true;
|
|
1446
|
+
}
|
|
1447
|
+
/** How far a facelet's surface sits from the center of its cubie. */
|
|
1448
|
+
#faceletDistance() {
|
|
1449
|
+
return this.#stickerless() ? cubieBodyDimensions.halfWidth * cubieBodyDimensions.pieceScale : cubieDimensions.stickerElevation;
|
|
1450
|
+
}
|
|
1197
1451
|
/** @deprecated */
|
|
1198
1452
|
experimentalSetFoundationOpacity(opacity) {
|
|
1199
1453
|
if (this.experimentalFoundationMeshes.length === 0) {
|
|
@@ -1238,16 +1492,14 @@ var Cube3D = class extends Object3D {
|
|
|
1238
1492
|
};
|
|
1239
1493
|
|
|
1240
1494
|
// src/cubing/twisty/views/3D/puzzles/CubePieces.ts
|
|
1241
|
-
import { BufferAttribute as
|
|
1242
|
-
import { BufferGeometry as
|
|
1495
|
+
import { BufferAttribute as BufferAttribute4 } from "three/src/core/BufferAttribute.js";
|
|
1496
|
+
import { BufferGeometry as BufferGeometry4 } from "three/src/core/BufferGeometry.js";
|
|
1243
1497
|
import { Matrix4 as Matrix42 } from "three/src/math/Matrix4.js";
|
|
1244
|
-
import { Vector3 as
|
|
1498
|
+
import { Vector3 as Vector35 } from "three/src/math/Vector3.js";
|
|
1245
1499
|
|
|
1246
1500
|
// src/cubing/twisty/views/3D/puzzles/StickerlessPlan.ts
|
|
1247
1501
|
var HINT_FACELET_ELEVATION = 0.5;
|
|
1248
1502
|
var HINT_FACELET_SCALE = 0.85;
|
|
1249
|
-
var BODY_MATERIAL_INDEX = 0;
|
|
1250
|
-
var HINT_MATERIAL_INDEX = 1;
|
|
1251
1503
|
var faceletMeshStickeringMasks = [
|
|
1252
1504
|
"regular",
|
|
1253
1505
|
"dim",
|
|
@@ -1343,6 +1595,7 @@ function paintInternal(colors, ranges) {
|
|
|
1343
1595
|
// src/cubing/twisty/views/3D/puzzles/CubePieces.ts
|
|
1344
1596
|
var PG_SCALE = 0.5;
|
|
1345
1597
|
var FACE_COUNT = 6;
|
|
1598
|
+
var LOGO_ELEVATION2 = 0.01;
|
|
1346
1599
|
function faceIdxForNormal(x, y, z) {
|
|
1347
1600
|
for (let faceIdx = 0; faceIdx < FACE_COUNT; faceIdx++) {
|
|
1348
1601
|
const { vector } = cubeFaceStyles[faceIdx];
|
|
@@ -1379,20 +1632,20 @@ function cubeLayout(stickerDat) {
|
|
|
1379
1632
|
const faceColors = new Array(FACE_COUNT);
|
|
1380
1633
|
const cubiesByPiece = /* @__PURE__ */ new Map();
|
|
1381
1634
|
const cubies = [];
|
|
1382
|
-
const
|
|
1635
|
+
const centroid2 = [0, 0, 0];
|
|
1383
1636
|
for (const sticker of stickers) {
|
|
1384
1637
|
const { coords } = sticker;
|
|
1385
1638
|
for (let axis = 0; axis < 3; axis++) {
|
|
1386
|
-
|
|
1639
|
+
centroid2[axis] = (coords[axis] + coords[axis + 3] + coords[axis + 6] + coords[axis + 9]) / 4;
|
|
1387
1640
|
}
|
|
1388
1641
|
let normalAxis = 0;
|
|
1389
1642
|
for (let axis = 1; axis < 3; axis++) {
|
|
1390
|
-
if (Math.abs(
|
|
1643
|
+
if (Math.abs(centroid2[axis]) > Math.abs(centroid2[normalAxis])) {
|
|
1391
1644
|
normalAxis = axis;
|
|
1392
1645
|
}
|
|
1393
1646
|
}
|
|
1394
|
-
const outward = Math.sign(
|
|
1395
|
-
const center = new
|
|
1647
|
+
const outward = Math.sign(centroid2[normalAxis]);
|
|
1648
|
+
const center = new Vector35();
|
|
1396
1649
|
for (let axis = 0; axis < 3; axis++) {
|
|
1397
1650
|
let expected;
|
|
1398
1651
|
if (axis === normalAxis) {
|
|
@@ -1400,7 +1653,7 @@ function cubeLayout(stickerDat) {
|
|
|
1400
1653
|
center.setComponent(axis, outward * (halfExtent - slotWidth / 2));
|
|
1401
1654
|
} else {
|
|
1402
1655
|
const slot = Math.round(
|
|
1403
|
-
(
|
|
1656
|
+
(centroid2[axis] + halfExtent) / slotWidth - 0.5
|
|
1404
1657
|
);
|
|
1405
1658
|
if (slot < 0 || slot >= layers) {
|
|
1406
1659
|
return null;
|
|
@@ -1408,7 +1661,7 @@ function cubeLayout(stickerDat) {
|
|
|
1408
1661
|
expected = -halfExtent + (slot + 0.5) * slotWidth;
|
|
1409
1662
|
center.setComponent(axis, expected);
|
|
1410
1663
|
}
|
|
1411
|
-
if (Math.abs(
|
|
1664
|
+
if (Math.abs(centroid2[axis] - expected) > epsilon) {
|
|
1412
1665
|
return null;
|
|
1413
1666
|
}
|
|
1414
1667
|
const halfSpan = axis === normalAxis ? 0 : slotWidth / 2;
|
|
@@ -1470,7 +1723,6 @@ function newCubieShape(outwardFaces, slotWidth) {
|
|
|
1470
1723
|
cubieBodyDimensions.roundingSegments
|
|
1471
1724
|
);
|
|
1472
1725
|
const bodyPositions = body.getAttribute("position").array;
|
|
1473
|
-
const bodyNormals = body.getAttribute("normal").array;
|
|
1474
1726
|
const bodyIndices = Array.from(body.getIndex().array);
|
|
1475
1727
|
const faceVertexRanges = [];
|
|
1476
1728
|
for (const group of body.groups) {
|
|
@@ -1482,20 +1734,29 @@ function newCubieShape(outwardFaces, slotWidth) {
|
|
|
1482
1734
|
}
|
|
1483
1735
|
faceVertexRanges[group.materialIndex] = { start, count: end - start };
|
|
1484
1736
|
}
|
|
1485
|
-
const
|
|
1486
|
-
const
|
|
1487
|
-
const indices = bodyIndices.slice();
|
|
1737
|
+
const hintPositions = [];
|
|
1738
|
+
const hintIndices = [];
|
|
1488
1739
|
const hintVertexRanges = /* @__PURE__ */ new Map();
|
|
1489
1740
|
const hintHalfWidth = HINT_FACELET_SCALE * slotWidth / 2;
|
|
1490
1741
|
const hintDistance = slotWidth / 2 + HINT_FACELET_ELEVATION;
|
|
1491
|
-
const
|
|
1492
|
-
const
|
|
1493
|
-
const
|
|
1742
|
+
const logoSurfaces = /* @__PURE__ */ new Map();
|
|
1743
|
+
const faceDistance = cubieBodyDimensions.halfWidth * cubieBodyDimensions.pieceScale * slotWidth;
|
|
1744
|
+
const u = new Vector35();
|
|
1745
|
+
const v = new Vector35();
|
|
1746
|
+
const corner = new Vector35();
|
|
1494
1747
|
for (const faceIdx of outwardFaces) {
|
|
1495
1748
|
const normal2 = cubeFaceStyles[faceIdx].vector;
|
|
1496
1749
|
u.set(normal2.y, normal2.z, normal2.x);
|
|
1497
1750
|
v.crossVectors(normal2, u);
|
|
1498
|
-
|
|
1751
|
+
logoSurfaces.set(
|
|
1752
|
+
faceIdx,
|
|
1753
|
+
rectangleLogoSurface(
|
|
1754
|
+
normal2.clone().multiplyScalar(faceDistance + LOGO_ELEVATION2 * slotWidth),
|
|
1755
|
+
u.clone().multiplyScalar(slotWidth / 2),
|
|
1756
|
+
v.clone().multiplyScalar(slotWidth / 2)
|
|
1757
|
+
)
|
|
1758
|
+
);
|
|
1759
|
+
const start = hintPositions.length / 3;
|
|
1499
1760
|
for (const [su, sv] of [
|
|
1500
1761
|
[-1, -1],
|
|
1501
1762
|
[1, -1],
|
|
@@ -1503,58 +1764,57 @@ function newCubieShape(outwardFaces, slotWidth) {
|
|
|
1503
1764
|
[-1, 1]
|
|
1504
1765
|
]) {
|
|
1505
1766
|
corner.copy(normal2).multiplyScalar(hintDistance).addScaledVector(u, su * hintHalfWidth).addScaledVector(v, sv * hintHalfWidth);
|
|
1506
|
-
|
|
1507
|
-
normals.push(normal2.x, normal2.y, normal2.z);
|
|
1767
|
+
hintPositions.push(corner.x, corner.y, corner.z);
|
|
1508
1768
|
}
|
|
1509
|
-
|
|
1769
|
+
hintIndices.push(start, start + 1, start + 2, start, start + 2, start + 3);
|
|
1510
1770
|
hintVertexRanges.set(faceIdx, { start, count: 4 });
|
|
1511
1771
|
}
|
|
1512
1772
|
body.dispose();
|
|
1513
1773
|
return {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1774
|
+
bodyPosition: new BufferAttribute4(bodyPositions.slice(), 3),
|
|
1775
|
+
bodyIndex: new BufferAttribute4(new Uint16Array(bodyIndices), 1),
|
|
1776
|
+
bodyVertexCount: bodyPositions.length / 3,
|
|
1777
|
+
hintPosition: new BufferAttribute4(new Float32Array(hintPositions), 3),
|
|
1778
|
+
hintIndex: new BufferAttribute4(new Uint16Array(hintIndices), 1),
|
|
1779
|
+
hintVertexCount: hintPositions.length / 3,
|
|
1520
1780
|
faceVertexRanges,
|
|
1521
|
-
hintVertexRanges
|
|
1781
|
+
hintVertexRanges,
|
|
1782
|
+
logoSurfaces
|
|
1522
1783
|
};
|
|
1523
1784
|
}
|
|
1785
|
+
function newPieceMesh(position, index, vertexCount) {
|
|
1786
|
+
const geometry = new BufferGeometry4();
|
|
1787
|
+
geometry.setAttribute("position", position);
|
|
1788
|
+
geometry.setIndex(index);
|
|
1789
|
+
const colors = new BufferAttribute4(new Uint8Array(4 * vertexCount), 4, true);
|
|
1790
|
+
geometry.setAttribute("color", colors);
|
|
1791
|
+
return { geometry, colors };
|
|
1792
|
+
}
|
|
1524
1793
|
function newCubiePiece(cubie, shape) {
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
const colors = new BufferAttribute3(
|
|
1530
|
-
new Uint8Array(4 * shape.vertexCount),
|
|
1531
|
-
4,
|
|
1532
|
-
true
|
|
1794
|
+
const body = newPieceMesh(
|
|
1795
|
+
shape.bodyPosition,
|
|
1796
|
+
shape.bodyIndex,
|
|
1797
|
+
shape.bodyVertexCount
|
|
1533
1798
|
);
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
if (shape.hintIndexCount > 0) {
|
|
1537
|
-
geometry.addGroup(
|
|
1538
|
-
shape.bodyIndexCount,
|
|
1539
|
-
shape.hintIndexCount,
|
|
1540
|
-
HINT_MATERIAL_INDEX
|
|
1541
|
-
);
|
|
1542
|
-
}
|
|
1543
|
-
paintInternal(colors, shape.faceVertexRanges);
|
|
1799
|
+
const hint = shape.hintVertexCount > 0 ? newPieceMesh(shape.hintPosition, shape.hintIndex, shape.hintVertexCount) : null;
|
|
1800
|
+
paintInternal(body.colors, shape.faceVertexRanges);
|
|
1544
1801
|
const facelets = cubie.stickers.map((sticker) => ({
|
|
1545
1802
|
ori: sticker.ori,
|
|
1546
1803
|
faceStyle: sticker.faceIdx,
|
|
1547
1804
|
// A duplicate shares its square with the real facelet, which is the one
|
|
1548
1805
|
// that gets painted.
|
|
1549
1806
|
body: sticker.isDup ? [] : [shape.faceVertexRanges[sticker.faceIdx]],
|
|
1550
|
-
hint: sticker.isDup ? [] : [shape.hintVertexRanges.get(sticker.faceIdx)].filter(Boolean)
|
|
1807
|
+
hint: sticker.isDup ? [] : [shape.hintVertexRanges.get(sticker.faceIdx)].filter(Boolean),
|
|
1808
|
+
// Set for a duplicate too: it is the same square, seen through another of
|
|
1809
|
+
// the piece's facelets.
|
|
1810
|
+
logo: shape.logoSurfaces.get(sticker.faceIdx) ?? null
|
|
1551
1811
|
}));
|
|
1552
1812
|
return {
|
|
1553
1813
|
orbit: cubie.orbit,
|
|
1554
1814
|
ord: cubie.ord,
|
|
1555
1815
|
home: new Matrix42().setPosition(cubie.center),
|
|
1556
|
-
|
|
1557
|
-
|
|
1816
|
+
body,
|
|
1817
|
+
hint,
|
|
1558
1818
|
facelets
|
|
1559
1819
|
};
|
|
1560
1820
|
}
|
|
@@ -1584,23 +1844,23 @@ function cubePuzzlePlan(stickerDat) {
|
|
|
1584
1844
|
}
|
|
1585
1845
|
|
|
1586
1846
|
// src/cubing/twisty/views/3D/puzzles/PG3D.ts
|
|
1587
|
-
import { DoubleSide as DoubleSide2, FrontSide as
|
|
1588
|
-
import { BufferAttribute as
|
|
1589
|
-
import { BufferGeometry as
|
|
1847
|
+
import { DoubleSide as DoubleSide2, FrontSide as FrontSide3 } from "three/src/constants.js";
|
|
1848
|
+
import { BufferAttribute as BufferAttribute5 } from "three/src/core/BufferAttribute.js";
|
|
1849
|
+
import { BufferGeometry as BufferGeometry5 } from "three/src/core/BufferGeometry.js";
|
|
1590
1850
|
import { Object3D as Object3D2 } from "three/src/core/Object3D.js";
|
|
1591
|
-
import { MeshBasicMaterial as
|
|
1851
|
+
import { MeshBasicMaterial as MeshBasicMaterial4 } from "three/src/materials/MeshBasicMaterial.js";
|
|
1592
1852
|
import { Color as Color3 } from "three/src/math/Color.js";
|
|
1593
|
-
import { Vector3 as
|
|
1853
|
+
import { Vector3 as Vector36 } from "three/src/math/Vector3.js";
|
|
1594
1854
|
import { Group as Group2 } from "three/src/objects/Group.js";
|
|
1595
|
-
import { Mesh as
|
|
1596
|
-
var foundationMaterial = new
|
|
1855
|
+
import { Mesh as Mesh3 } from "three/src/objects/Mesh.js";
|
|
1856
|
+
var foundationMaterial = new MeshBasicMaterial4({
|
|
1597
1857
|
side: DoubleSide2,
|
|
1598
1858
|
color: 0
|
|
1599
1859
|
});
|
|
1600
|
-
var invisMaterial = new
|
|
1860
|
+
var invisMaterial = new MeshBasicMaterial4({
|
|
1601
1861
|
visible: false
|
|
1602
1862
|
});
|
|
1603
|
-
var basicStickerMaterial = new
|
|
1863
|
+
var basicStickerMaterial = new MeshBasicMaterial4({
|
|
1604
1864
|
vertexColors: true
|
|
1605
1865
|
});
|
|
1606
1866
|
function dist(coords, a, b) {
|
|
@@ -1735,9 +1995,9 @@ var Filler = class {
|
|
|
1735
1995
|
}
|
|
1736
1996
|
}
|
|
1737
1997
|
setAttributes(geo) {
|
|
1738
|
-
geo.setAttribute("position", new
|
|
1998
|
+
geo.setAttribute("position", new BufferAttribute5(this.vertices, 3));
|
|
1739
1999
|
const sa2 = this.colors.subarray(0, 9 * this.sz);
|
|
1740
|
-
geo.setAttribute("color", new
|
|
2000
|
+
geo.setAttribute("color", new BufferAttribute5(sa2, 3, true));
|
|
1741
2001
|
}
|
|
1742
2002
|
makeGroups(geo) {
|
|
1743
2003
|
geo.clearGroups();
|
|
@@ -1963,9 +2223,9 @@ var HitPlaneDef = class {
|
|
|
1963
2223
|
filler.addUncolored(coords, g);
|
|
1964
2224
|
filler.addUncolored(coords, g + 1);
|
|
1965
2225
|
}
|
|
1966
|
-
this.geo = new
|
|
2226
|
+
this.geo = new BufferGeometry5();
|
|
1967
2227
|
filler.setAttributes(this.geo);
|
|
1968
|
-
const obj = new
|
|
2228
|
+
const obj = new Mesh3(this.geo, invisMaterial);
|
|
1969
2229
|
obj.userData["quantumMove"] = stickerDat.notationMapper.notationToExternal(
|
|
1970
2230
|
new Move(hitface.name)
|
|
1971
2231
|
);
|
|
@@ -1978,7 +2238,7 @@ var AxisInfo2 = class {
|
|
|
1978
2238
|
order;
|
|
1979
2239
|
constructor(axisDat) {
|
|
1980
2240
|
const vec = axisDat.coordinates;
|
|
1981
|
-
this.axis = new
|
|
2241
|
+
this.axis = new Vector36(vec[0], vec[1], vec[2]);
|
|
1982
2242
|
this.order = axisDat.order;
|
|
1983
2243
|
}
|
|
1984
2244
|
};
|
|
@@ -1995,7 +2255,7 @@ var PG3D = class extends Object3D2 {
|
|
|
1995
2255
|
if (stickerDat.stickers.length === 0) {
|
|
1996
2256
|
throw Error("Reuse of stickerdat from pg; please don't do that.");
|
|
1997
2257
|
}
|
|
1998
|
-
this.hintMaterial = new
|
|
2258
|
+
this.hintMaterial = new MeshBasicMaterial4({
|
|
1999
2259
|
vertexColors: true,
|
|
2000
2260
|
transparent: true,
|
|
2001
2261
|
opacity: 0.5
|
|
@@ -2083,13 +2343,13 @@ var PG3D = class extends Object3D2 {
|
|
|
2083
2343
|
this.stickers[orbit][ori][ord].addFoundation(filler, sticker, black);
|
|
2084
2344
|
}
|
|
2085
2345
|
}
|
|
2086
|
-
const fixedGeo = new
|
|
2346
|
+
const fixedGeo = new BufferGeometry5();
|
|
2087
2347
|
filler.setAttributes(fixedGeo);
|
|
2088
2348
|
filler.makeGroups(fixedGeo);
|
|
2089
|
-
const obj = new
|
|
2349
|
+
const obj = new Mesh3(fixedGeo, this.materialArray1);
|
|
2090
2350
|
obj.scale.set(PG_SCALE2, PG_SCALE2, PG_SCALE2);
|
|
2091
2351
|
this.add(obj);
|
|
2092
|
-
const obj2 = new
|
|
2352
|
+
const obj2 = new Mesh3(fixedGeo, this.materialArray2);
|
|
2093
2353
|
obj2.scale.set(PG_SCALE2, PG_SCALE2, PG_SCALE2);
|
|
2094
2354
|
this.add(obj2);
|
|
2095
2355
|
const hitfaces = this.stickerDat.faces;
|
|
@@ -2180,7 +2440,7 @@ var PG3D = class extends Object3D2 {
|
|
|
2180
2440
|
}
|
|
2181
2441
|
}
|
|
2182
2442
|
for (const axis of this.stickerDat.axis) {
|
|
2183
|
-
const product = point.dot(new
|
|
2443
|
+
const product = point.dot(new Vector36(...axis.coordinates));
|
|
2184
2444
|
if (product > closestMoveDotProduct) {
|
|
2185
2445
|
const modified = this.stickerDat.notationMapper.notationToExternal(
|
|
2186
2446
|
modify(axis.quantumMove)
|
|
@@ -2414,7 +2674,7 @@ var PG3D = class extends Object3D2 {
|
|
|
2414
2674
|
} else if (v === 1) {
|
|
2415
2675
|
this.hintMaterial = this.stickerMaterial;
|
|
2416
2676
|
} else {
|
|
2417
|
-
this.hintMaterial = new
|
|
2677
|
+
this.hintMaterial = new MeshBasicMaterial4({
|
|
2418
2678
|
vertexColors: true,
|
|
2419
2679
|
transparent: true,
|
|
2420
2680
|
opacity: v
|
|
@@ -2462,7 +2722,7 @@ var PG3D = class extends Object3D2 {
|
|
|
2462
2722
|
}
|
|
2463
2723
|
filler.uvs.copyWithin(6 * filler.sz, 0, 6 * filler.sz);
|
|
2464
2724
|
const sa1 = filler.uvs.subarray(0, 6 * filler.sz);
|
|
2465
|
-
this.fixedGeo.setAttribute("uv", new
|
|
2725
|
+
this.fixedGeo.setAttribute("uv", new BufferAttribute5(sa1, 2, true));
|
|
2466
2726
|
}
|
|
2467
2727
|
experimentalUpdateTexture(enabled, stickerTexture, hintTexture) {
|
|
2468
2728
|
if (!stickerTexture) {
|
|
@@ -2477,9 +2737,9 @@ var PG3D = class extends Object3D2 {
|
|
|
2477
2737
|
this.stickerMaterialDisposable = false;
|
|
2478
2738
|
}
|
|
2479
2739
|
if (enabled) {
|
|
2480
|
-
this.stickerMaterial = new
|
|
2740
|
+
this.stickerMaterial = new MeshBasicMaterial4({
|
|
2481
2741
|
map: stickerTexture,
|
|
2482
|
-
side:
|
|
2742
|
+
side: FrontSide3,
|
|
2483
2743
|
transparent: false
|
|
2484
2744
|
});
|
|
2485
2745
|
this.stickerMaterialDisposable = true;
|
|
@@ -2491,9 +2751,9 @@ var PG3D = class extends Object3D2 {
|
|
|
2491
2751
|
this.hintMaterialDisposable = false;
|
|
2492
2752
|
}
|
|
2493
2753
|
if (enabled) {
|
|
2494
|
-
this.hintMaterial = new
|
|
2754
|
+
this.hintMaterial = new MeshBasicMaterial4({
|
|
2495
2755
|
map: hintTexture,
|
|
2496
|
-
side:
|
|
2756
|
+
side: FrontSide3,
|
|
2497
2757
|
transparent: true
|
|
2498
2758
|
});
|
|
2499
2759
|
this.hintMaterialDisposable = true;
|
|
@@ -2513,21 +2773,21 @@ var PG3D = class extends Object3D2 {
|
|
|
2513
2773
|
};
|
|
2514
2774
|
|
|
2515
2775
|
// src/cubing/twisty/views/3D/puzzles/SolidPieces.ts
|
|
2516
|
-
import { BufferAttribute as
|
|
2517
|
-
import { BufferGeometry as
|
|
2776
|
+
import { BufferAttribute as BufferAttribute6 } from "three/src/core/BufferAttribute.js";
|
|
2777
|
+
import { BufferGeometry as BufferGeometry6 } from "three/src/core/BufferGeometry.js";
|
|
2518
2778
|
import { Color as Color4 } from "three/src/math/Color.js";
|
|
2519
2779
|
import { Matrix4 as Matrix43 } from "three/src/math/Matrix4.js";
|
|
2520
|
-
import { Vector3 as
|
|
2780
|
+
import { Vector3 as Vector38 } from "three/src/math/Vector3.js";
|
|
2521
2781
|
|
|
2522
2782
|
// src/cubing/twisty/views/3D/puzzles/SolidPieceGeometry.ts
|
|
2523
|
-
import { Vector3 as
|
|
2783
|
+
import { Vector3 as Vector37 } from "three/src/math/Vector3.js";
|
|
2524
2784
|
var SOLID_PIECE_GROOVE = 0.018;
|
|
2525
2785
|
var SOLID_PIECE_CHAMFER = 5e-3;
|
|
2526
2786
|
var BOX_PLANE = -1;
|
|
2527
2787
|
function boxFacet(planeIdx, normal2, size) {
|
|
2528
|
-
const reference = Math.abs(normal2.y) > 0.5 ? new
|
|
2529
|
-
const u = new
|
|
2530
|
-
const v = new
|
|
2788
|
+
const reference = Math.abs(normal2.y) > 0.5 ? new Vector37(0, 0, 1) : new Vector37(0, 1, 0);
|
|
2789
|
+
const u = new Vector37().crossVectors(reference, normal2).normalize();
|
|
2790
|
+
const v = new Vector37().crossVectors(normal2, u);
|
|
2531
2791
|
const center = normal2.clone().multiplyScalar(size);
|
|
2532
2792
|
return {
|
|
2533
2793
|
plane: planeIdx,
|
|
@@ -2542,23 +2802,23 @@ function boxFacet(planeIdx, normal2, size) {
|
|
|
2542
2802
|
};
|
|
2543
2803
|
}
|
|
2544
2804
|
var BOX_NORMALS = [
|
|
2545
|
-
new
|
|
2546
|
-
new
|
|
2547
|
-
new
|
|
2548
|
-
new
|
|
2549
|
-
new
|
|
2550
|
-
new
|
|
2805
|
+
new Vector37(1, 0, 0),
|
|
2806
|
+
new Vector37(-1, 0, 0),
|
|
2807
|
+
new Vector37(0, 1, 0),
|
|
2808
|
+
new Vector37(0, -1, 0),
|
|
2809
|
+
new Vector37(0, 0, 1),
|
|
2810
|
+
new Vector37(0, 0, -1)
|
|
2551
2811
|
];
|
|
2552
2812
|
function orderInPlane(points, normal2) {
|
|
2553
|
-
const
|
|
2813
|
+
const centroid2 = new Vector37();
|
|
2554
2814
|
for (const point of points) {
|
|
2555
|
-
|
|
2815
|
+
centroid2.addScaledVector(point, 1 / points.length);
|
|
2556
2816
|
}
|
|
2557
|
-
const reference = new
|
|
2558
|
-
const other = new
|
|
2559
|
-
const offset = new
|
|
2817
|
+
const reference = new Vector37().subVectors(points[0], centroid2).normalize();
|
|
2818
|
+
const other = new Vector37().crossVectors(normal2, reference);
|
|
2819
|
+
const offset = new Vector37();
|
|
2560
2820
|
return points.map((point) => {
|
|
2561
|
-
offset.subVectors(point,
|
|
2821
|
+
offset.subVectors(point, centroid2);
|
|
2562
2822
|
return {
|
|
2563
2823
|
point,
|
|
2564
2824
|
angle: Math.atan2(offset.dot(other), offset.dot(reference))
|
|
@@ -2660,7 +2920,7 @@ function chamferPlanes(facets, planes, chamfer, epsilon) {
|
|
|
2660
2920
|
continue;
|
|
2661
2921
|
}
|
|
2662
2922
|
seen.add(pairKey);
|
|
2663
|
-
const sum = new
|
|
2923
|
+
const sum = new Vector37().addVectors(
|
|
2664
2924
|
planes[colored].normal,
|
|
2665
2925
|
planes[internal].normal
|
|
2666
2926
|
);
|
|
@@ -2690,11 +2950,9 @@ function solidPieceGeometry(planes, options) {
|
|
|
2690
2950
|
const withChamfers = options.chamfer > 0 ? working.concat(chamferPlanes(plain, working, options.chamfer, epsilon)) : working;
|
|
2691
2951
|
const facets = (options.chamfer > 0 ? buildFacets(withChamfers, options.radius, epsilon) : plain) ?? plain;
|
|
2692
2952
|
const positions = [];
|
|
2693
|
-
const normals = [];
|
|
2694
2953
|
const ranges = planes.map(() => []);
|
|
2695
2954
|
const internalRanges = [];
|
|
2696
2955
|
for (const facet of facets) {
|
|
2697
|
-
const plane = withChamfers[facet.plane];
|
|
2698
2956
|
const start = positions.length / 3;
|
|
2699
2957
|
for (let i = 1; i < facet.vertices.length - 1; i++) {
|
|
2700
2958
|
for (const vertex of [
|
|
@@ -2703,22 +2961,20 @@ function solidPieceGeometry(planes, options) {
|
|
|
2703
2961
|
facet.vertices[i + 1]
|
|
2704
2962
|
]) {
|
|
2705
2963
|
positions.push(vertex.x, vertex.y, vertex.z);
|
|
2706
|
-
normals.push(plane.normal.x, plane.normal.y, plane.normal.z);
|
|
2707
2964
|
}
|
|
2708
2965
|
}
|
|
2709
2966
|
const range = { start, count: positions.length / 3 - start };
|
|
2710
2967
|
if (range.count === 0) {
|
|
2711
2968
|
continue;
|
|
2712
2969
|
}
|
|
2713
|
-
if (plane.source === -1) {
|
|
2970
|
+
if (withChamfers[facet.plane].source === -1) {
|
|
2714
2971
|
internalRanges.push(range);
|
|
2715
2972
|
} else {
|
|
2716
|
-
ranges[plane.source].push(range);
|
|
2973
|
+
ranges[withChamfers[facet.plane].source].push(range);
|
|
2717
2974
|
}
|
|
2718
2975
|
}
|
|
2719
2976
|
return {
|
|
2720
2977
|
positions: new Float32Array(positions),
|
|
2721
|
-
normals: new Float32Array(normals),
|
|
2722
2978
|
vertexCount: positions.length / 3,
|
|
2723
2979
|
ranges,
|
|
2724
2980
|
internalRanges
|
|
@@ -2727,9 +2983,10 @@ function solidPieceGeometry(planes, options) {
|
|
|
2727
2983
|
|
|
2728
2984
|
// src/cubing/twisty/views/3D/puzzles/SolidPieces.ts
|
|
2729
2985
|
var PG_SCALE3 = 0.5;
|
|
2730
|
-
var
|
|
2986
|
+
var EPSILON2 = 1e-6;
|
|
2987
|
+
var LOGO_ELEVATION3 = 0.01;
|
|
2731
2988
|
function vertexAt(sticker, index) {
|
|
2732
|
-
return new
|
|
2989
|
+
return new Vector38(
|
|
2733
2990
|
sticker.coords[3 * index],
|
|
2734
2991
|
sticker.coords[3 * index + 1],
|
|
2735
2992
|
sticker.coords[3 * index + 2]
|
|
@@ -2743,11 +3000,11 @@ function polygonOf(sticker) {
|
|
|
2743
3000
|
return vertices;
|
|
2744
3001
|
}
|
|
2745
3002
|
function outwardNormal(polygon) {
|
|
2746
|
-
const normal2 = new
|
|
2747
|
-
new
|
|
2748
|
-
new
|
|
3003
|
+
const normal2 = new Vector38().crossVectors(
|
|
3004
|
+
new Vector38().subVectors(polygon[1], polygon[0]),
|
|
3005
|
+
new Vector38().subVectors(polygon[2], polygon[0])
|
|
2749
3006
|
);
|
|
2750
|
-
if (normal2.length() <
|
|
3007
|
+
if (normal2.length() < EPSILON2) {
|
|
2751
3008
|
return null;
|
|
2752
3009
|
}
|
|
2753
3010
|
normal2.normalize();
|
|
@@ -2788,13 +3045,13 @@ function faceStyles(faceNormals, faceColors) {
|
|
|
2788
3045
|
return styles;
|
|
2789
3046
|
}
|
|
2790
3047
|
function hintPolygon(polygon, normal2) {
|
|
2791
|
-
const
|
|
3048
|
+
const centroid2 = new Vector38();
|
|
2792
3049
|
for (const vertex of polygon) {
|
|
2793
|
-
|
|
3050
|
+
centroid2.addScaledVector(vertex, 1 / polygon.length);
|
|
2794
3051
|
}
|
|
2795
3052
|
return polygon.map(
|
|
2796
|
-
(vertex) =>
|
|
2797
|
-
new
|
|
3053
|
+
(vertex) => centroid2.clone().addScaledVector(
|
|
3054
|
+
new Vector38().subVectors(vertex, centroid2),
|
|
2798
3055
|
HINT_FACELET_SCALE
|
|
2799
3056
|
).addScaledVector(normal2, HINT_FACELET_ELEVATION)
|
|
2800
3057
|
);
|
|
@@ -2805,6 +3062,8 @@ function solidPuzzlePlan(stickerDat) {
|
|
|
2805
3062
|
return null;
|
|
2806
3063
|
}
|
|
2807
3064
|
let radius = 0;
|
|
3065
|
+
let faceletArea = 0;
|
|
3066
|
+
let faceletCount = 0;
|
|
2808
3067
|
for (const sticker of stickers) {
|
|
2809
3068
|
if (sticker.coords.length < 9 || sticker.coords.length % 3 !== 0) {
|
|
2810
3069
|
return null;
|
|
@@ -2867,6 +3126,10 @@ function solidPuzzlePlan(stickerDat) {
|
|
|
2867
3126
|
if (faceColors[sticker.face] !== sticker.color) {
|
|
2868
3127
|
return null;
|
|
2869
3128
|
}
|
|
3129
|
+
faceletCount++;
|
|
3130
|
+
for (let i = 1; i < polygon.length - 1; i++) {
|
|
3131
|
+
faceletArea += new Vector38().subVectors(polygon[i], polygon[0]).cross(new Vector38().subVectors(polygon[i + 1], polygon[0])).length() / 2;
|
|
3132
|
+
}
|
|
2870
3133
|
piece.stickers.push({ sticker, polygon });
|
|
2871
3134
|
for (let i = 0; i < polygon.length; i++) {
|
|
2872
3135
|
const edgeKey = [
|
|
@@ -2885,16 +3148,30 @@ function solidPuzzlePlan(stickerDat) {
|
|
|
2885
3148
|
if (!styles) {
|
|
2886
3149
|
return null;
|
|
2887
3150
|
}
|
|
2888
|
-
const
|
|
2889
|
-
|
|
3151
|
+
const featureScale = Math.min(
|
|
3152
|
+
faceDistance,
|
|
3153
|
+
1.5 * Math.sqrt(faceletArea / faceletCount)
|
|
3154
|
+
);
|
|
3155
|
+
const cuts = cutPlanes(
|
|
3156
|
+
order,
|
|
3157
|
+
edges,
|
|
3158
|
+
stickerDat.axis.map((axis) => new Vector38(...axis.coordinates).normalize()),
|
|
3159
|
+
quantum
|
|
2890
3160
|
);
|
|
3161
|
+
if (!cuts) {
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
2891
3164
|
const plans = [];
|
|
2892
3165
|
for (const piece of order) {
|
|
2893
|
-
const plan = newSolidPiece(
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
3166
|
+
const plan = newSolidPiece(
|
|
3167
|
+
piece,
|
|
3168
|
+
{ planes: cuts, edges },
|
|
3169
|
+
{
|
|
3170
|
+
quantum,
|
|
3171
|
+
radius,
|
|
3172
|
+
featureScale
|
|
3173
|
+
}
|
|
3174
|
+
);
|
|
2898
3175
|
if (!plan) {
|
|
2899
3176
|
return null;
|
|
2900
3177
|
}
|
|
@@ -2902,19 +3179,82 @@ function solidPuzzlePlan(stickerDat) {
|
|
|
2902
3179
|
}
|
|
2903
3180
|
return { faceStyles: styles, pieces: plans, scale: PG_SCALE3 };
|
|
2904
3181
|
}
|
|
2905
|
-
function
|
|
3182
|
+
function cutPlanes(pieces, edges, axes, quantum) {
|
|
3183
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3184
|
+
const boundaryEdges = [];
|
|
3185
|
+
for (const piece of pieces) {
|
|
3186
|
+
const pieceKey = `${piece.orbit}/${piece.ord}`;
|
|
3187
|
+
for (const { polygon } of piece.stickers) {
|
|
3188
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
3189
|
+
const a = polygon[i];
|
|
3190
|
+
const b = polygon[(i + 1) % polygon.length];
|
|
3191
|
+
const sharing = edges.get(
|
|
3192
|
+
[keyOf(a, quantum), keyOf(b, quantum)].sort().join("|")
|
|
3193
|
+
);
|
|
3194
|
+
if (!sharing || ![...sharing].some((key) => key !== pieceKey)) {
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
boundaryEdges.push([a, b]);
|
|
3198
|
+
for (const axis of axes) {
|
|
3199
|
+
if (Math.abs(a.dot(axis) - b.dot(axis)) > quantum) {
|
|
3200
|
+
continue;
|
|
3201
|
+
}
|
|
3202
|
+
const offset = a.dot(axis);
|
|
3203
|
+
const key = `${keyOf(axis, 1e-4)}|${Math.round(offset / quantum)}`;
|
|
3204
|
+
const candidate = candidates.get(key);
|
|
3205
|
+
if (candidate) {
|
|
3206
|
+
candidate.uses++;
|
|
3207
|
+
} else {
|
|
3208
|
+
candidates.set(key, { normal: axis, offset, uses: 1 });
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
const cuts = [...candidates.values()].sort((a, b) => b.uses - a.uses);
|
|
3215
|
+
const kept = cuts.filter(({ normal: normal2, offset }) => {
|
|
3216
|
+
for (const piece of pieces) {
|
|
3217
|
+
let above = false;
|
|
3218
|
+
let below = false;
|
|
3219
|
+
for (const { polygon } of piece.stickers) {
|
|
3220
|
+
let onIt = true;
|
|
3221
|
+
for (const vertex of polygon) {
|
|
3222
|
+
above ||= vertex.dot(normal2) > offset + quantum;
|
|
3223
|
+
below ||= vertex.dot(normal2) < offset - quantum;
|
|
3224
|
+
onIt &&= Math.abs(vertex.dot(normal2) - offset) <= quantum;
|
|
3225
|
+
}
|
|
3226
|
+
if (onIt) {
|
|
3227
|
+
return false;
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
if (above && below) {
|
|
3231
|
+
return false;
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
return true;
|
|
3235
|
+
});
|
|
3236
|
+
for (const [a, b] of boundaryEdges) {
|
|
3237
|
+
const covered = kept.some(
|
|
3238
|
+
({ normal: normal2, offset }) => Math.abs(a.dot(normal2) - offset) < quantum && Math.abs(b.dot(normal2) - offset) < quantum
|
|
3239
|
+
);
|
|
3240
|
+
if (!covered) {
|
|
3241
|
+
return null;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
return kept;
|
|
3245
|
+
}
|
|
3246
|
+
function newSolidPiece(piece, cuts, sizes) {
|
|
2906
3247
|
if (piece.stickers.length === 0) {
|
|
2907
3248
|
return null;
|
|
2908
3249
|
}
|
|
2909
|
-
const pieceKey = `${piece.orbit}/${piece.ord}`;
|
|
2910
3250
|
const planes = [];
|
|
2911
3251
|
const planeOfSticker = /* @__PURE__ */ new Map();
|
|
2912
|
-
const interior = new
|
|
3252
|
+
const interior = new Vector38();
|
|
2913
3253
|
for (const { polygon } of piece.stickers) {
|
|
2914
3254
|
for (const vertex of polygon) {
|
|
2915
3255
|
interior.addScaledVector(
|
|
2916
3256
|
vertex,
|
|
2917
|
-
|
|
3257
|
+
1 / polygon.length / piece.stickers.length
|
|
2918
3258
|
);
|
|
2919
3259
|
}
|
|
2920
3260
|
}
|
|
@@ -2927,100 +3267,113 @@ function newSolidPiece(piece, edges, axes, sizes) {
|
|
|
2927
3267
|
color: sticker.face
|
|
2928
3268
|
});
|
|
2929
3269
|
}
|
|
3270
|
+
const pieceKey = `${piece.orbit}/${piece.ord}`;
|
|
2930
3271
|
for (const { polygon } of piece.stickers) {
|
|
2931
3272
|
for (let i = 0; i < polygon.length; i++) {
|
|
2932
3273
|
const a = polygon[i];
|
|
2933
3274
|
const b = polygon[(i + 1) % polygon.length];
|
|
2934
|
-
const
|
|
2935
|
-
|
|
2936
|
-
|
|
3275
|
+
const sharing = cuts.edges.get(
|
|
3276
|
+
[keyOf(a, sizes.quantum), keyOf(b, sizes.quantum)].sort().join("|")
|
|
3277
|
+
);
|
|
3278
|
+
if (!sharing || ![...sharing].some((key) => key !== pieceKey)) {
|
|
2937
3279
|
continue;
|
|
2938
3280
|
}
|
|
2939
|
-
const
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
normal2.normalize();
|
|
2944
|
-
if (normal2.dot(interior) > 0) {
|
|
2945
|
-
normal2.negate();
|
|
2946
|
-
}
|
|
2947
|
-
if (!axes.some((axis) => Math.abs(axis.dot(normal2)) > 0.9999)) {
|
|
3281
|
+
const cut = cuts.planes.find(
|
|
3282
|
+
({ normal: normal3, offset: offset2 }) => Math.abs(a.dot(normal3) - offset2) < sizes.quantum && Math.abs(b.dot(normal3) - offset2) < sizes.quantum
|
|
3283
|
+
);
|
|
3284
|
+
if (!cut) {
|
|
2948
3285
|
return null;
|
|
2949
3286
|
}
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
return null;
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
3287
|
+
const outward = interior.dot(cut.normal) < cut.offset;
|
|
3288
|
+
const normal2 = outward ? cut.normal.clone() : cut.normal.clone().negate();
|
|
3289
|
+
const offset = outward ? cut.offset : -cut.offset;
|
|
2957
3290
|
if (planes.some(
|
|
2958
|
-
(plane) => plane.color === null && plane.normal.dot(normal2) > 0.9999 && Math.abs(plane.offset) < sizes.quantum
|
|
3291
|
+
(plane) => plane.color === null && plane.normal.dot(normal2) > 0.9999 && Math.abs(plane.offset - offset) < sizes.quantum
|
|
2959
3292
|
)) {
|
|
2960
3293
|
continue;
|
|
2961
3294
|
}
|
|
2962
|
-
planes.push({ normal: normal2, offset
|
|
3295
|
+
planes.push({ normal: normal2, offset, color: null });
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
for (const cut of cuts.planes) {
|
|
3299
|
+
let touches = false;
|
|
3300
|
+
let above = false;
|
|
3301
|
+
let below = false;
|
|
3302
|
+
for (const { polygon } of piece.stickers) {
|
|
3303
|
+
for (const vertex of polygon) {
|
|
3304
|
+
const side = vertex.dot(cut.normal) - cut.offset;
|
|
3305
|
+
if (Math.abs(side) <= sizes.quantum) {
|
|
3306
|
+
touches = true;
|
|
3307
|
+
} else if (side > 0) {
|
|
3308
|
+
above = true;
|
|
3309
|
+
} else {
|
|
3310
|
+
below = true;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
if (touches || above === below) {
|
|
3315
|
+
continue;
|
|
2963
3316
|
}
|
|
3317
|
+
planes.push(
|
|
3318
|
+
above ? {
|
|
3319
|
+
normal: cut.normal.clone().negate(),
|
|
3320
|
+
offset: -cut.offset,
|
|
3321
|
+
color: null
|
|
3322
|
+
} : { normal: cut.normal.clone(), offset: cut.offset, color: null }
|
|
3323
|
+
);
|
|
2964
3324
|
}
|
|
2965
3325
|
const solid = solidPieceGeometry(planes, {
|
|
2966
|
-
groove: SOLID_PIECE_GROOVE * sizes.
|
|
2967
|
-
chamfer: SOLID_PIECE_CHAMFER * sizes.
|
|
3326
|
+
groove: SOLID_PIECE_GROOVE * sizes.featureScale,
|
|
3327
|
+
chamfer: SOLID_PIECE_CHAMFER * sizes.featureScale,
|
|
2968
3328
|
radius: sizes.radius
|
|
2969
3329
|
});
|
|
2970
3330
|
if (!solid) {
|
|
2971
3331
|
return null;
|
|
2972
3332
|
}
|
|
2973
|
-
const
|
|
2974
|
-
const normals = Array.from(solid.normals);
|
|
3333
|
+
const hintPositions = [];
|
|
2975
3334
|
const hintRanges = /* @__PURE__ */ new Map();
|
|
2976
3335
|
for (const { sticker, polygon } of piece.stickers) {
|
|
2977
3336
|
const normal2 = outwardNormal(polygon);
|
|
2978
|
-
const
|
|
2979
|
-
const start =
|
|
2980
|
-
for (let i = 1; i <
|
|
2981
|
-
for (const vertex of [
|
|
2982
|
-
|
|
2983
|
-
normals.push(normal2.x, normal2.y, normal2.z);
|
|
3337
|
+
const hint2 = hintPolygon(polygon, normal2);
|
|
3338
|
+
const start = hintPositions.length / 3;
|
|
3339
|
+
for (let i = 1; i < hint2.length - 1; i++) {
|
|
3340
|
+
for (const vertex of [hint2[0], hint2[i], hint2[i + 1]]) {
|
|
3341
|
+
hintPositions.push(vertex.x, vertex.y, vertex.z);
|
|
2984
3342
|
}
|
|
2985
3343
|
}
|
|
2986
3344
|
hintRanges.set(sticker, {
|
|
2987
3345
|
start,
|
|
2988
|
-
count:
|
|
3346
|
+
count: hintPositions.length / 3 - start
|
|
2989
3347
|
});
|
|
2990
3348
|
}
|
|
2991
|
-
const
|
|
2992
|
-
const
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
geometry.addGroup(0, solid.vertexCount, BODY_MATERIAL_INDEX);
|
|
3004
|
-
if (vertexCount > solid.vertexCount) {
|
|
3005
|
-
geometry.addGroup(
|
|
3006
|
-
solid.vertexCount,
|
|
3007
|
-
vertexCount - solid.vertexCount,
|
|
3008
|
-
HINT_MATERIAL_INDEX
|
|
3349
|
+
const body = newPieceMesh2(solid.positions);
|
|
3350
|
+
const hint = hintPositions.length > 0 ? newPieceMesh2(new Float32Array(hintPositions)) : null;
|
|
3351
|
+
paintInternal(body.colors, solid.internalRanges);
|
|
3352
|
+
const logoByFace = /* @__PURE__ */ new Map();
|
|
3353
|
+
for (const { sticker, polygon } of piece.stickers) {
|
|
3354
|
+
logoByFace.set(
|
|
3355
|
+
sticker.face,
|
|
3356
|
+
logoSurface(
|
|
3357
|
+
polygon,
|
|
3358
|
+
outwardNormal(polygon),
|
|
3359
|
+
LOGO_ELEVATION3 * sizes.featureScale
|
|
3360
|
+
)
|
|
3009
3361
|
);
|
|
3010
3362
|
}
|
|
3011
|
-
paintInternal(colors, solid.internalRanges);
|
|
3012
3363
|
const facelets = piece.stickers.map(({ sticker }) => ({
|
|
3013
3364
|
ori: sticker.ori,
|
|
3014
3365
|
faceStyle: sticker.face,
|
|
3015
3366
|
body: solid.ranges[planeOfSticker.get(sticker)],
|
|
3016
|
-
hint: [hintRanges.get(sticker)]
|
|
3367
|
+
hint: [hintRanges.get(sticker)],
|
|
3368
|
+
logo: logoByFace.get(sticker.face) ?? null
|
|
3017
3369
|
}));
|
|
3018
3370
|
for (const sticker of piece.duplicates) {
|
|
3019
3371
|
facelets.push({
|
|
3020
3372
|
ori: sticker.ori,
|
|
3021
3373
|
faceStyle: sticker.face,
|
|
3022
3374
|
body: [],
|
|
3023
|
-
hint: []
|
|
3375
|
+
hint: [],
|
|
3376
|
+
logo: logoByFace.get(sticker.face) ?? null
|
|
3024
3377
|
});
|
|
3025
3378
|
}
|
|
3026
3379
|
return {
|
|
@@ -3028,23 +3381,34 @@ function newSolidPiece(piece, edges, axes, sizes) {
|
|
|
3028
3381
|
ord: piece.ord,
|
|
3029
3382
|
// The geometry is already where the piece belongs.
|
|
3030
3383
|
home: new Matrix43(),
|
|
3031
|
-
|
|
3032
|
-
|
|
3384
|
+
body,
|
|
3385
|
+
hint,
|
|
3033
3386
|
facelets
|
|
3034
3387
|
};
|
|
3035
3388
|
}
|
|
3389
|
+
function newPieceMesh2(positions) {
|
|
3390
|
+
const geometry = new BufferGeometry6();
|
|
3391
|
+
geometry.setAttribute("position", new BufferAttribute6(positions, 3));
|
|
3392
|
+
const colors = new BufferAttribute6(
|
|
3393
|
+
new Uint8Array(4 * positions.length / 3),
|
|
3394
|
+
4,
|
|
3395
|
+
true
|
|
3396
|
+
);
|
|
3397
|
+
geometry.setAttribute("color", colors);
|
|
3398
|
+
return { geometry, colors };
|
|
3399
|
+
}
|
|
3036
3400
|
|
|
3037
3401
|
// src/cubing/twisty/views/3D/puzzles/Square1_3D.ts
|
|
3038
3402
|
import { DoubleSide as DoubleSide3 } from "three/src/constants.js";
|
|
3039
|
-
import { BufferAttribute as
|
|
3040
|
-
import { BufferGeometry as
|
|
3403
|
+
import { BufferAttribute as BufferAttribute7 } from "three/src/core/BufferAttribute.js";
|
|
3404
|
+
import { BufferGeometry as BufferGeometry7 } from "three/src/core/BufferGeometry.js";
|
|
3041
3405
|
import { Object3D as Object3D3 } from "three/src/core/Object3D.js";
|
|
3042
|
-
import { MeshBasicMaterial as
|
|
3406
|
+
import { MeshBasicMaterial as MeshBasicMaterial5 } from "three/src/materials/MeshBasicMaterial.js";
|
|
3043
3407
|
import { Color as Color5 } from "three/src/math/Color.js";
|
|
3044
3408
|
import { Quaternion as Quaternion2 } from "three/src/math/Quaternion.js";
|
|
3045
|
-
import { Vector3 as
|
|
3409
|
+
import { Vector3 as Vector39 } from "three/src/math/Vector3.js";
|
|
3046
3410
|
import { Group as Group3 } from "three/src/objects/Group.js";
|
|
3047
|
-
import { Mesh as
|
|
3411
|
+
import { Mesh as Mesh4 } from "three/src/objects/Mesh.js";
|
|
3048
3412
|
var DEGREE = TAU / 360;
|
|
3049
3413
|
var SLOT_ANGLE_DEGREES = 30;
|
|
3050
3414
|
var WEDGES_PER_LAYER = 12;
|
|
@@ -3059,8 +3423,8 @@ var RING_COLORS = [2254591, 16750848, 65280, 16711680];
|
|
|
3059
3423
|
var FRAME_OFFSET_DEGREES = 180;
|
|
3060
3424
|
var BODY_COLOR = 1118481;
|
|
3061
3425
|
var MIRROR = -1;
|
|
3062
|
-
var Y_AXIS = new
|
|
3063
|
-
var SLICE_AXIS = new
|
|
3426
|
+
var Y_AXIS = new Vector39(0, 1, 0);
|
|
3427
|
+
var SLICE_AXIS = new Vector39(
|
|
3064
3428
|
MIRROR * Math.sin(15 * DEGREE),
|
|
3065
3429
|
0,
|
|
3066
3430
|
Math.cos(15 * DEGREE)
|
|
@@ -3077,7 +3441,7 @@ function slotQuaternion(slot) {
|
|
|
3077
3441
|
);
|
|
3078
3442
|
if (slot >= WEDGES_PER_LAYER) {
|
|
3079
3443
|
quaternion.multiply(
|
|
3080
|
-
new Quaternion2().setFromAxisAngle(new
|
|
3444
|
+
new Quaternion2().setFromAxisAngle(new Vector39(0, 0, 1), TAU / 2)
|
|
3081
3445
|
);
|
|
3082
3446
|
}
|
|
3083
3447
|
return quaternion;
|
|
@@ -3166,15 +3530,15 @@ function prismStickerSpecs(spec) {
|
|
|
3166
3530
|
const specs = [];
|
|
3167
3531
|
if (topColor !== null) {
|
|
3168
3532
|
specs.push({
|
|
3169
|
-
corners: polygon.map(([x, z]) => new
|
|
3170
|
-
normal: new
|
|
3533
|
+
corners: polygon.map(([x, z]) => new Vector39(x, yTop, z)),
|
|
3534
|
+
normal: new Vector39(0, 1, 0),
|
|
3171
3535
|
color: topColor
|
|
3172
3536
|
});
|
|
3173
3537
|
}
|
|
3174
3538
|
if (bottomColor !== null) {
|
|
3175
3539
|
specs.push({
|
|
3176
|
-
corners: polygon.map(([x, z]) => new
|
|
3177
|
-
normal: new
|
|
3540
|
+
corners: polygon.map(([x, z]) => new Vector39(x, yBottom, z)),
|
|
3541
|
+
normal: new Vector39(0, -1, 0),
|
|
3178
3542
|
color: bottomColor
|
|
3179
3543
|
});
|
|
3180
3544
|
}
|
|
@@ -3191,17 +3555,17 @@ function prismStickerSpecs(spec) {
|
|
|
3191
3555
|
}
|
|
3192
3556
|
const [x0, z0] = polygon[i];
|
|
3193
3557
|
const [x1, z1] = polygon[(i + 1) % polygon.length];
|
|
3194
|
-
const normal2 = new
|
|
3558
|
+
const normal2 = new Vector39(z1 - z0, 0, -(x1 - x0)).normalize();
|
|
3195
3559
|
const outward = normal2.x * ((x0 + x1) / 2 - centroidX) + normal2.z * ((z0 + z1) / 2 - centroidZ);
|
|
3196
3560
|
if (outward < 0) {
|
|
3197
3561
|
normal2.negate();
|
|
3198
3562
|
}
|
|
3199
3563
|
specs.push({
|
|
3200
3564
|
corners: [
|
|
3201
|
-
new
|
|
3202
|
-
new
|
|
3203
|
-
new
|
|
3204
|
-
new
|
|
3565
|
+
new Vector39(x0, yBottom, z0),
|
|
3566
|
+
new Vector39(x1, yBottom, z1),
|
|
3567
|
+
new Vector39(x1, yTop, z1),
|
|
3568
|
+
new Vector39(x0, yTop, z0)
|
|
3205
3569
|
],
|
|
3206
3570
|
normal: normal2,
|
|
3207
3571
|
color
|
|
@@ -3210,7 +3574,7 @@ function prismStickerSpecs(spec) {
|
|
|
3210
3574
|
return specs;
|
|
3211
3575
|
}
|
|
3212
3576
|
function stickerPositions(spec, faceletScale) {
|
|
3213
|
-
const center = new
|
|
3577
|
+
const center = new Vector39();
|
|
3214
3578
|
for (const corner of spec.corners) {
|
|
3215
3579
|
center.addScaledVector(corner, 1 / spec.corners.length);
|
|
3216
3580
|
}
|
|
@@ -3239,9 +3603,9 @@ var PUZZLE_RADIUS = CUBE_HALF_EDGE * Math.SQRT2;
|
|
|
3239
3603
|
function prismPlanes(spec) {
|
|
3240
3604
|
const { polygon, sideColors } = spec;
|
|
3241
3605
|
const planes = [
|
|
3242
|
-
{ normal: new
|
|
3606
|
+
{ normal: new Vector39(0, 1, 0), offset: spec.yTop, color: spec.topColor },
|
|
3243
3607
|
{
|
|
3244
|
-
normal: new
|
|
3608
|
+
normal: new Vector39(0, -1, 0),
|
|
3245
3609
|
offset: -spec.yBottom,
|
|
3246
3610
|
color: spec.bottomColor
|
|
3247
3611
|
}
|
|
@@ -3255,7 +3619,7 @@ function prismPlanes(spec) {
|
|
|
3255
3619
|
for (let i = 0; i < polygon.length; i++) {
|
|
3256
3620
|
const [x0, z0] = polygon[i];
|
|
3257
3621
|
const [x1, z1] = polygon[(i + 1) % polygon.length];
|
|
3258
|
-
const normal2 = new
|
|
3622
|
+
const normal2 = new Vector39(z1 - z0, 0, -(x1 - x0)).normalize();
|
|
3259
3623
|
if (normal2.x * (x0 - centroidX) + normal2.z * (z0 - centroidZ) < 0) {
|
|
3260
3624
|
normal2.negate();
|
|
3261
3625
|
}
|
|
@@ -3295,13 +3659,12 @@ function stickerlessPieceGeometry(spec) {
|
|
|
3295
3659
|
paint(piece.ranges[i], color);
|
|
3296
3660
|
}
|
|
3297
3661
|
}
|
|
3298
|
-
const geometry = new
|
|
3299
|
-
geometry.setAttribute("position", new
|
|
3300
|
-
geometry.setAttribute("
|
|
3301
|
-
geometry.setAttribute("color", new BufferAttribute6(colors, 4, true));
|
|
3662
|
+
const geometry = new BufferGeometry7();
|
|
3663
|
+
geometry.setAttribute("position", new BufferAttribute7(piece.positions, 3));
|
|
3664
|
+
geometry.setAttribute("color", new BufferAttribute7(colors, 4, true));
|
|
3302
3665
|
return geometry;
|
|
3303
3666
|
}
|
|
3304
|
-
var bodyMaterial = new
|
|
3667
|
+
var bodyMaterial = new MeshBasicMaterial5({
|
|
3305
3668
|
color: new Color5(BODY_COLOR).convertLinearToSRGB(),
|
|
3306
3669
|
side: DoubleSide3
|
|
3307
3670
|
});
|
|
@@ -3313,7 +3676,7 @@ var stickerMaterialCache = /* @__PURE__ */ new Map();
|
|
|
3313
3676
|
function stickerMaterial(color) {
|
|
3314
3677
|
let material = stickerMaterialCache.get(color);
|
|
3315
3678
|
if (!material) {
|
|
3316
|
-
material = new
|
|
3679
|
+
material = new MeshBasicMaterial5({
|
|
3317
3680
|
color: new Color5(color).convertLinearToSRGB(),
|
|
3318
3681
|
side: DoubleSide3
|
|
3319
3682
|
});
|
|
@@ -3328,28 +3691,28 @@ var Square1Piece = class extends Group3 {
|
|
|
3328
3691
|
constructor(spec, faceletScale, stickerless) {
|
|
3329
3692
|
super();
|
|
3330
3693
|
if (stickerless) {
|
|
3331
|
-
this.body = new
|
|
3694
|
+
this.body = new Mesh4(
|
|
3332
3695
|
stickerlessPieceGeometry(spec),
|
|
3333
3696
|
stickerlessMaterial()
|
|
3334
3697
|
);
|
|
3335
3698
|
this.add(this.body);
|
|
3336
3699
|
return;
|
|
3337
3700
|
}
|
|
3338
|
-
const bodyGeometry = new
|
|
3701
|
+
const bodyGeometry = new BufferGeometry7();
|
|
3339
3702
|
bodyGeometry.setAttribute(
|
|
3340
3703
|
"position",
|
|
3341
|
-
new
|
|
3704
|
+
new BufferAttribute7(prismBodyPositions(spec), 3)
|
|
3342
3705
|
);
|
|
3343
|
-
this.body = new
|
|
3706
|
+
this.body = new Mesh4(bodyGeometry, bodyMaterial);
|
|
3344
3707
|
this.add(this.body);
|
|
3345
3708
|
this.#stickerSpecs = prismStickerSpecs(spec);
|
|
3346
3709
|
for (const stickerSpec of this.#stickerSpecs) {
|
|
3347
|
-
const geometry = new
|
|
3710
|
+
const geometry = new BufferGeometry7();
|
|
3348
3711
|
geometry.setAttribute(
|
|
3349
3712
|
"position",
|
|
3350
|
-
new
|
|
3713
|
+
new BufferAttribute7(stickerPositions(stickerSpec, faceletScale), 3)
|
|
3351
3714
|
);
|
|
3352
|
-
const mesh = new
|
|
3715
|
+
const mesh = new Mesh4(geometry, stickerMaterial(stickerSpec.color));
|
|
3353
3716
|
this.#stickerMeshes.push(mesh);
|
|
3354
3717
|
this.add(mesh);
|
|
3355
3718
|
}
|
|
@@ -3359,7 +3722,7 @@ var Square1Piece = class extends Group3 {
|
|
|
3359
3722
|
const geometry = this.#stickerMeshes[i].geometry;
|
|
3360
3723
|
geometry.setAttribute(
|
|
3361
3724
|
"position",
|
|
3362
|
-
new
|
|
3725
|
+
new BufferAttribute7(
|
|
3363
3726
|
stickerPositions(this.#stickerSpecs[i], faceletScale),
|
|
3364
3727
|
3
|
|
3365
3728
|
)
|
|
@@ -3414,6 +3777,38 @@ function equatorPrismSpec(homePiece) {
|
|
|
3414
3777
|
]
|
|
3415
3778
|
};
|
|
3416
3779
|
}
|
|
3780
|
+
var LOGO_EQUATOR_PIECE = 0;
|
|
3781
|
+
var LOGO_ELEVATION4 = 2 * STICKER_ELEVATION;
|
|
3782
|
+
function equatorLogoSurface(spec) {
|
|
3783
|
+
const { polygon, yBottom, yTop, sideColors } = spec;
|
|
3784
|
+
let best = null;
|
|
3785
|
+
let bestWidth = 0;
|
|
3786
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
3787
|
+
if (sideColors[i] === null || sideColors[i] === void 0) {
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
const [x0, z0] = polygon[i];
|
|
3791
|
+
const [x1, z1] = polygon[(i + 1) % polygon.length];
|
|
3792
|
+
const width = Math.hypot(x1 - x0, z1 - z0);
|
|
3793
|
+
if (width <= bestWidth) {
|
|
3794
|
+
continue;
|
|
3795
|
+
}
|
|
3796
|
+
const normal2 = new Vector39(z1 - z0, 0, -(x1 - x0)).normalize();
|
|
3797
|
+
const u = new Vector39(x1 - x0, 0, z1 - z0).multiplyScalar(0.5);
|
|
3798
|
+
const v = new Vector39(0, (yTop - yBottom) / 2, 0);
|
|
3799
|
+
if (new Vector39().crossVectors(u, v).dot(normal2) < 0) {
|
|
3800
|
+
u.negate();
|
|
3801
|
+
}
|
|
3802
|
+
const center = new Vector39(
|
|
3803
|
+
(x0 + x1) / 2,
|
|
3804
|
+
(yBottom + yTop) / 2,
|
|
3805
|
+
(z0 + z1) / 2
|
|
3806
|
+
).addScaledVector(normal2, LOGO_ELEVATION4);
|
|
3807
|
+
bestWidth = width;
|
|
3808
|
+
best = rectangleLogoSurface(center, u, v);
|
|
3809
|
+
}
|
|
3810
|
+
return best;
|
|
3811
|
+
}
|
|
3417
3812
|
function ringColorAt(phiDegrees) {
|
|
3418
3813
|
const faceIndex = Math.round(phiDegrees / 90);
|
|
3419
3814
|
return RING_COLORS[(faceIndex % 4 + 4) % 4];
|
|
@@ -3468,9 +3863,6 @@ var Square1_3D = class extends Object3D3 {
|
|
|
3468
3863
|
this.#equatorPieces.push(equator);
|
|
3469
3864
|
this.add(equator);
|
|
3470
3865
|
}
|
|
3471
|
-
if (this.#stickerless) {
|
|
3472
|
-
addCubieBodyLighting(this);
|
|
3473
|
-
}
|
|
3474
3866
|
this.scale.set(PUZZLE_SCALE, PUZZLE_SCALE, PUZZLE_SCALE);
|
|
3475
3867
|
}
|
|
3476
3868
|
scheduleRenderCallback;
|
|
@@ -3573,6 +3965,31 @@ var Square1_3D = class extends Object3D3 {
|
|
|
3573
3965
|
}
|
|
3574
3966
|
setStickeringMask(_stickeringMask) {
|
|
3575
3967
|
}
|
|
3968
|
+
#logoMesh = null;
|
|
3969
|
+
/**
|
|
3970
|
+
* Prints a logo on the equator block, or takes it off again when passed
|
|
3971
|
+
* `null`.
|
|
3972
|
+
*
|
|
3973
|
+
* The image is stretched onto a square sized to the face, so its own
|
|
3974
|
+
* proportions don't matter. It is a child of the piece, so it turns and flips
|
|
3975
|
+
* with the equator.
|
|
3976
|
+
*/
|
|
3977
|
+
experimentalSetLogo(texture) {
|
|
3978
|
+
if (this.#logoMesh) {
|
|
3979
|
+
this.#logoMesh.removeFromParent();
|
|
3980
|
+
this.#logoMesh.material.dispose();
|
|
3981
|
+
this.#logoMesh = null;
|
|
3982
|
+
}
|
|
3983
|
+
if (texture) {
|
|
3984
|
+
const surface = equatorLogoSurface(equatorPrismSpec(LOGO_EQUATOR_PIECE));
|
|
3985
|
+
if (surface) {
|
|
3986
|
+
this.#logoMesh = newLogoMesh(texture);
|
|
3987
|
+
surfaceMatrix(surface, this.#logoMesh.matrix);
|
|
3988
|
+
this.#equatorPieces[LOGO_EQUATOR_PIECE].add(this.#logoMesh);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
this.scheduleRenderCallback?.();
|
|
3992
|
+
}
|
|
3576
3993
|
experimentalUpdateOptions(options) {
|
|
3577
3994
|
let changed = false;
|
|
3578
3995
|
if (typeof options.showFoundation === "boolean") {
|
|
@@ -3607,14 +4024,32 @@ var Square1_3D = class extends Object3D3 {
|
|
|
3607
4024
|
|
|
3608
4025
|
// src/cubing/twisty/views/3D/puzzles/Stickerless3D.ts
|
|
3609
4026
|
import { BackSide as BackSide2 } from "three/src/constants.js";
|
|
3610
|
-
import { BufferAttribute as
|
|
3611
|
-
import { BufferGeometry as
|
|
4027
|
+
import { BufferAttribute as BufferAttribute8 } from "three/src/core/BufferAttribute.js";
|
|
4028
|
+
import { BufferGeometry as BufferGeometry8 } from "three/src/core/BufferGeometry.js";
|
|
3612
4029
|
import { Object3D as Object3D4 } from "three/src/core/Object3D.js";
|
|
3613
|
-
import { MeshBasicMaterial as
|
|
4030
|
+
import { MeshBasicMaterial as MeshBasicMaterial6 } from "three/src/materials/MeshBasicMaterial.js";
|
|
3614
4031
|
import { Matrix4 as Matrix44 } from "three/src/math/Matrix4.js";
|
|
3615
|
-
import { Vector3 as
|
|
3616
|
-
import {
|
|
3617
|
-
|
|
4032
|
+
import { Vector3 as Vector310 } from "three/src/math/Vector3.js";
|
|
4033
|
+
import { BatchedMesh } from "three/src/objects/BatchedMesh.js";
|
|
4034
|
+
import { Mesh as Mesh5 } from "three/src/objects/Mesh.js";
|
|
4035
|
+
var invisibleMaterial2 = new MeshBasicMaterial6({ visible: false });
|
|
4036
|
+
function newBatch(meshes, material) {
|
|
4037
|
+
let vertices = 0;
|
|
4038
|
+
let indices = 0;
|
|
4039
|
+
for (const { geometry } of meshes) {
|
|
4040
|
+
vertices += geometry.getAttribute("position").count;
|
|
4041
|
+
indices += geometry.getIndex()?.count ?? 0;
|
|
4042
|
+
}
|
|
4043
|
+
return new BatchedMesh(meshes.length, vertices, indices, material);
|
|
4044
|
+
}
|
|
4045
|
+
function addToBatch(batch, mesh, home) {
|
|
4046
|
+
const geometryId = batch.addGeometry(mesh.geometry);
|
|
4047
|
+
const instance = batch.addInstance(geometryId);
|
|
4048
|
+
batch.setMatrixAt(instance, home);
|
|
4049
|
+
mesh.geometry.dispose();
|
|
4050
|
+
const range = batch.getGeometryRangeAt(geometryId);
|
|
4051
|
+
return { instance, vertexStart: range.vertexStart };
|
|
4052
|
+
}
|
|
3618
4053
|
var Stickerless3D = class extends Object3D4 {
|
|
3619
4054
|
constructor(scheduleRenderCallback, kpuzzle, stickerDat, plan, options = {}) {
|
|
3620
4055
|
super();
|
|
@@ -3622,7 +4057,8 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3622
4057
|
this.kpuzzle = kpuzzle;
|
|
3623
4058
|
this.stickerDat = stickerDat;
|
|
3624
4059
|
this.plan = plan;
|
|
3625
|
-
this.#
|
|
4060
|
+
this.#logoFacelet = options.logoFacelet ?? null;
|
|
4061
|
+
this.#hintMaterial = new MeshBasicMaterial6({
|
|
3626
4062
|
vertexColors: true,
|
|
3627
4063
|
transparent: true,
|
|
3628
4064
|
// Hint facelets show the faces turned away from the camera, so they are
|
|
@@ -3630,20 +4066,35 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3630
4066
|
side: BackSide2
|
|
3631
4067
|
});
|
|
3632
4068
|
this.#bodyMaterial = newVertexColorBodyMaterial();
|
|
3633
|
-
this.#materials = [this.#bodyMaterial, this.#hintMaterial];
|
|
3634
|
-
this.experimentalUpdateOptions({
|
|
3635
|
-
hintFacelets: options.hintFacelets ?? "floating"
|
|
3636
|
-
});
|
|
3637
4069
|
for (const axis of stickerDat.axis) {
|
|
3638
4070
|
this.#axesInfo[axis.quantumMove.family] = {
|
|
3639
|
-
axis: new
|
|
4071
|
+
axis: new Vector310(...axis.coordinates),
|
|
3640
4072
|
order: axis.order
|
|
3641
4073
|
};
|
|
3642
4074
|
}
|
|
4075
|
+
this.#bodyBatch = newBatch(
|
|
4076
|
+
plan.pieces.map((piecePlan) => piecePlan.body),
|
|
4077
|
+
this.#bodyMaterial
|
|
4078
|
+
);
|
|
4079
|
+
this.#bodyBatch.sortObjects = false;
|
|
4080
|
+
this.#bodyBatch.perObjectFrustumCulled = false;
|
|
4081
|
+
this.add(this.#bodyBatch);
|
|
4082
|
+
const hints = plan.pieces.map((piecePlan) => piecePlan.hint).filter((hint) => hint !== null);
|
|
4083
|
+
if (hints.length > 0) {
|
|
4084
|
+
this.#hintBatch = newBatch(hints, this.#hintMaterial);
|
|
4085
|
+
this.#hintBatch.perObjectFrustumCulled = false;
|
|
4086
|
+
this.add(this.#hintBatch);
|
|
4087
|
+
}
|
|
3643
4088
|
for (const piecePlan of plan.pieces) {
|
|
3644
4089
|
this.#addPiece(piecePlan);
|
|
3645
4090
|
}
|
|
3646
|
-
|
|
4091
|
+
this.#bodyColors = this.#bodyBatch.geometry.getAttribute(
|
|
4092
|
+
"color"
|
|
4093
|
+
);
|
|
4094
|
+
this.#hintColors = this.#hintBatch?.geometry.getAttribute("color") ?? null;
|
|
4095
|
+
this.experimentalUpdateOptions({
|
|
4096
|
+
hintFacelets: options.hintFacelets ?? "floating"
|
|
4097
|
+
});
|
|
3647
4098
|
for (const face2 of stickerDat.faces) {
|
|
3648
4099
|
this.#addControlTarget(face2);
|
|
3649
4100
|
}
|
|
@@ -3657,11 +4108,19 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3657
4108
|
stickerDat;
|
|
3658
4109
|
plan;
|
|
3659
4110
|
#pieces = [];
|
|
4111
|
+
/**
|
|
4112
|
+
* One draw call for every piece of the puzzle, and one for every hint
|
|
4113
|
+
* facelet. A batch keeps a matrix per instance, so a move still moves the
|
|
4114
|
+
* pieces it sweeps and nothing else.
|
|
4115
|
+
*/
|
|
4116
|
+
#bodyBatch;
|
|
4117
|
+
#hintBatch = null;
|
|
4118
|
+
#bodyColors;
|
|
4119
|
+
#hintColors = null;
|
|
3660
4120
|
/** Indexed `[orbit][ori][ord]`, like the orbits of the `KPuzzle`. */
|
|
3661
4121
|
#facelets = {};
|
|
3662
4122
|
#axesInfo = {};
|
|
3663
4123
|
#controlTargets = [];
|
|
3664
|
-
#materials;
|
|
3665
4124
|
#bodyMaterial;
|
|
3666
4125
|
#hintMaterial;
|
|
3667
4126
|
#appearances = /* @__PURE__ */ new Map();
|
|
@@ -3669,29 +4128,50 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3669
4128
|
#turningPieces = [];
|
|
3670
4129
|
/** Which pieces each quantum move sweeps, by the move's notation. */
|
|
3671
4130
|
#turnedPieces = /* @__PURE__ */ new Map();
|
|
3672
|
-
|
|
4131
|
+
/** The span of each color attribute that changed, so only it is uploaded. */
|
|
4132
|
+
#dirtyColors = /* @__PURE__ */ new Map();
|
|
3673
4133
|
#lastPosition = null;
|
|
3674
4134
|
#pendingStickeringUpdate = false;
|
|
4135
|
+
/** The facelet a logo is printed on, and where it currently shows. */
|
|
4136
|
+
#logoFacelet = null;
|
|
4137
|
+
#logoMesh = null;
|
|
4138
|
+
#logoSlot = null;
|
|
4139
|
+
#logoSurfaceMatrix = new Matrix44();
|
|
3675
4140
|
#addPiece(plan) {
|
|
3676
|
-
const
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
4141
|
+
const bodyInstance = addToBatch(this.#bodyBatch, plan.body, plan.home);
|
|
4142
|
+
const hintInstance = plan.hint && this.#hintBatch ? addToBatch(this.#hintBatch, plan.hint, plan.home) : -1;
|
|
4143
|
+
const piece = {
|
|
4144
|
+
bodyInstance: bodyInstance.instance,
|
|
4145
|
+
hintInstance: hintInstance === -1 ? -1 : hintInstance.instance,
|
|
4146
|
+
home: plan.home,
|
|
4147
|
+
matrix: plan.home.clone(),
|
|
4148
|
+
turning: false
|
|
4149
|
+
};
|
|
3681
4150
|
this.#pieces.push(piece);
|
|
4151
|
+
const shift = (ranges, offset) => ranges.map((range) => ({
|
|
4152
|
+
start: range.start + offset,
|
|
4153
|
+
count: range.count
|
|
4154
|
+
}));
|
|
3682
4155
|
const orbitFacelets = this.#facelets[plan.orbit] ??= [];
|
|
3683
4156
|
for (const facelet of plan.facelets) {
|
|
3684
4157
|
(orbitFacelets[facelet.ori] ??= [])[plan.ord] = {
|
|
3685
4158
|
piece,
|
|
3686
4159
|
faceStyle: facelet.faceStyle,
|
|
3687
|
-
body: facelet.body,
|
|
3688
|
-
hint: facelet.hint,
|
|
4160
|
+
body: shift(facelet.body, bodyInstance.vertexStart),
|
|
4161
|
+
hint: hintInstance === -1 ? [] : shift(facelet.hint, hintInstance.vertexStart),
|
|
3689
4162
|
appearanceKey: -1,
|
|
3690
4163
|
mask: "regular",
|
|
3691
|
-
hintMask: "regular"
|
|
4164
|
+
hintMask: "regular",
|
|
4165
|
+
logo: facelet.logo
|
|
3692
4166
|
};
|
|
3693
4167
|
}
|
|
3694
4168
|
}
|
|
4169
|
+
#setMatrix(piece) {
|
|
4170
|
+
this.#bodyBatch.setMatrixAt(piece.bodyInstance, piece.matrix);
|
|
4171
|
+
if (piece.hintInstance !== -1) {
|
|
4172
|
+
this.#hintBatch.setMatrixAt(piece.hintInstance, piece.matrix);
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
3695
4175
|
#addControlTarget(face2) {
|
|
3696
4176
|
const { coords } = face2;
|
|
3697
4177
|
const triangles = coords.length / 3 - 2;
|
|
@@ -3707,18 +4187,98 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3707
4187
|
}
|
|
3708
4188
|
}
|
|
3709
4189
|
}
|
|
3710
|
-
const geometry = new
|
|
3711
|
-
geometry.setAttribute("position", new
|
|
3712
|
-
const mesh = new
|
|
4190
|
+
const geometry = new BufferGeometry8();
|
|
4191
|
+
geometry.setAttribute("position", new BufferAttribute8(positions, 3));
|
|
4192
|
+
const mesh = new Mesh5(geometry, invisibleMaterial2);
|
|
3713
4193
|
mesh.userData["quantumMove"] = this.stickerDat.notationMapper.notationToExternal(new Move(face2.name));
|
|
3714
4194
|
mesh.scale.setScalar(0.99);
|
|
3715
4195
|
this.add(mesh);
|
|
3716
4196
|
this.#controlTargets.push(mesh);
|
|
3717
4197
|
}
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
4198
|
+
/**
|
|
4199
|
+
* Prints a logo on the piece this puzzle keeps one on, or takes it off again
|
|
4200
|
+
* when passed `null`.
|
|
4201
|
+
*
|
|
4202
|
+
* The image is stretched onto the square {@link PuzzlePlan} sized for that
|
|
4203
|
+
* facelet, so its own proportions don't matter. It follows the piece: the
|
|
4204
|
+
* logo is drawn wherever the piece currently is, including part-way through a
|
|
4205
|
+
* move. The one thing it does not follow is a piece turning in place — a
|
|
4206
|
+
* megaminx or skewb center whose facelets are all one square — which leaves
|
|
4207
|
+
* the logo upright rather than rotating it with the plastic.
|
|
4208
|
+
*/
|
|
4209
|
+
experimentalSetLogo(texture) {
|
|
4210
|
+
if (!texture || !this.#logoFacelet) {
|
|
4211
|
+
this.#disposeLogo();
|
|
4212
|
+
this.scheduleRenderCallback();
|
|
4213
|
+
return;
|
|
4214
|
+
}
|
|
4215
|
+
if (this.#logoMesh) {
|
|
4216
|
+
const material = this.#logoMesh.material;
|
|
4217
|
+
material.map = texture;
|
|
4218
|
+
material.needsUpdate = true;
|
|
4219
|
+
} else {
|
|
4220
|
+
this.#logoMesh = newLogoMesh(texture);
|
|
4221
|
+
this.add(this.#logoMesh);
|
|
4222
|
+
}
|
|
4223
|
+
this.#updateLogoSlot();
|
|
4224
|
+
this.#placeLogo();
|
|
4225
|
+
this.scheduleRenderCallback();
|
|
4226
|
+
}
|
|
4227
|
+
#disposeLogo() {
|
|
4228
|
+
if (!this.#logoMesh) {
|
|
4229
|
+
return;
|
|
4230
|
+
}
|
|
4231
|
+
this.remove(this.#logoMesh);
|
|
4232
|
+
this.#logoMesh.material.dispose();
|
|
4233
|
+
this.#logoMesh = null;
|
|
4234
|
+
this.#logoSlot = null;
|
|
4235
|
+
}
|
|
4236
|
+
/** Which slot is showing the logo's facelet, as of the last position. */
|
|
4237
|
+
#updateLogoSlot() {
|
|
4238
|
+
this.#logoSlot = null;
|
|
4239
|
+
const address = this.#logoFacelet;
|
|
4240
|
+
const pattern = this.#lastPosition?.pattern;
|
|
4241
|
+
if (!address || !pattern) {
|
|
4242
|
+
return;
|
|
4243
|
+
}
|
|
4244
|
+
const orbitFacelets = this.#facelets[address.orbit];
|
|
4245
|
+
const orbitPattern = pattern.patternData[address.orbit];
|
|
4246
|
+
if (!orbitFacelets || !orbitPattern) {
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4249
|
+
const numOrientations = orbitFacelets.length;
|
|
4250
|
+
for (let ord = 0; ord < orbitPattern.pieces.length; ord++) {
|
|
4251
|
+
if (orbitPattern.pieces[ord] !== address.ord) {
|
|
4252
|
+
continue;
|
|
4253
|
+
}
|
|
4254
|
+
const ori = numOrientations === 1 ? 0 : (address.ori + orbitPattern.orientation[ord]) % numOrientations;
|
|
4255
|
+
this.#logoSlot = orbitFacelets[ori]?.[ord] ?? null;
|
|
4256
|
+
return;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
#placeLogo() {
|
|
4260
|
+
const mesh = this.#logoMesh;
|
|
4261
|
+
if (!mesh) {
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
const slot = this.#logoSlot;
|
|
4265
|
+
if (!slot?.logo) {
|
|
4266
|
+
mesh.visible = false;
|
|
4267
|
+
return;
|
|
3721
4268
|
}
|
|
4269
|
+
mesh.visible = true;
|
|
4270
|
+
mesh.matrix.multiplyMatrices(
|
|
4271
|
+
slot.piece.matrix,
|
|
4272
|
+
surfaceMatrix(slot.logo, this.#logoSurfaceMatrix)
|
|
4273
|
+
);
|
|
4274
|
+
mesh.matrixWorldNeedsUpdate = true;
|
|
4275
|
+
}
|
|
4276
|
+
dispose() {
|
|
4277
|
+
this.#disposeLogo();
|
|
4278
|
+
this.#bodyBatch.dispose();
|
|
4279
|
+
this.#bodyBatch.geometry.dispose();
|
|
4280
|
+
this.#hintBatch?.dispose();
|
|
4281
|
+
this.#hintBatch?.geometry.dispose();
|
|
3722
4282
|
this.#bodyMaterial.dispose();
|
|
3723
4283
|
this.#hintMaterial.dispose();
|
|
3724
4284
|
}
|
|
@@ -3751,7 +4311,7 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3751
4311
|
}
|
|
3752
4312
|
}
|
|
3753
4313
|
for (const axis of this.stickerDat.axis) {
|
|
3754
|
-
const product = point.dot(new
|
|
4314
|
+
const product = point.dot(new Vector310(...axis.coordinates));
|
|
3755
4315
|
if (product > closestMoveDotProduct) {
|
|
3756
4316
|
const modified = this.stickerDat.notationMapper.notationToExternal(
|
|
3757
4317
|
modify(axis.quantumMove)
|
|
@@ -3809,8 +4369,8 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3809
4369
|
}
|
|
3810
4370
|
/** @deprecated */
|
|
3811
4371
|
experimentalUpdateOptions(options) {
|
|
3812
|
-
if (options.hintFacelets !== void 0) {
|
|
3813
|
-
this.#
|
|
4372
|
+
if (options.hintFacelets !== void 0 && this.#hintBatch) {
|
|
4373
|
+
this.#hintBatch.visible = options.hintFacelets !== "none";
|
|
3814
4374
|
this.scheduleRenderCallback();
|
|
3815
4375
|
}
|
|
3816
4376
|
}
|
|
@@ -3828,11 +4388,13 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3828
4388
|
this.#updateColors(position);
|
|
3829
4389
|
this.#lastPosition = position;
|
|
3830
4390
|
this.#pendingStickeringUpdate = false;
|
|
4391
|
+
this.#updateLogoSlot();
|
|
3831
4392
|
}
|
|
3832
|
-
|
|
3833
|
-
|
|
4393
|
+
const wereTurning = this.#turningPieces;
|
|
4394
|
+
for (const piece of wereTurning) {
|
|
4395
|
+
piece.turning = false;
|
|
3834
4396
|
}
|
|
3835
|
-
this.#turningPieces
|
|
4397
|
+
this.#turningPieces = [];
|
|
3836
4398
|
const turnMatrix = new Matrix44();
|
|
3837
4399
|
for (const moveProgress of position.movesInProgress) {
|
|
3838
4400
|
const move = moveProgress.move;
|
|
@@ -3849,10 +4411,24 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3849
4411
|
-smootherStep(moveProgress.fraction) * moveProgress.direction * unswizzled.amount * TAU / axisInfo.order
|
|
3850
4412
|
);
|
|
3851
4413
|
for (const piece of this.#piecesTurnedBy(move)) {
|
|
3852
|
-
piece.
|
|
3853
|
-
|
|
4414
|
+
if (!piece.turning) {
|
|
4415
|
+
piece.turning = true;
|
|
4416
|
+
piece.matrix.copy(piece.home);
|
|
4417
|
+
this.#turningPieces.push(piece);
|
|
4418
|
+
}
|
|
4419
|
+
piece.matrix.premultiply(turnMatrix);
|
|
3854
4420
|
}
|
|
3855
4421
|
}
|
|
4422
|
+
for (const piece of wereTurning) {
|
|
4423
|
+
if (!piece.turning) {
|
|
4424
|
+
piece.matrix.copy(piece.home);
|
|
4425
|
+
this.#setMatrix(piece);
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
for (const piece of this.#turningPieces) {
|
|
4429
|
+
this.#setMatrix(piece);
|
|
4430
|
+
}
|
|
4431
|
+
this.#placeLogo();
|
|
3856
4432
|
this.scheduleRenderCallback();
|
|
3857
4433
|
}
|
|
3858
4434
|
/**
|
|
@@ -3935,17 +4511,34 @@ var Stickerless3D = class extends Object3D4 {
|
|
|
3935
4511
|
source.mask,
|
|
3936
4512
|
source.hintMask
|
|
3937
4513
|
);
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
4514
|
+
this.#paint(this.#bodyColors, slot.body, appearance, 0);
|
|
4515
|
+
if (this.#hintColors) {
|
|
4516
|
+
this.#paint(this.#hintColors, slot.hint, appearance, 4);
|
|
4517
|
+
}
|
|
3941
4518
|
}
|
|
3942
4519
|
}
|
|
3943
4520
|
}
|
|
3944
|
-
for (const colors of this.#dirtyColors) {
|
|
4521
|
+
for (const [colors, span] of this.#dirtyColors) {
|
|
4522
|
+
colors.addUpdateRange(4 * span.first, 4 * (span.last - span.first + 1));
|
|
3945
4523
|
colors.needsUpdate = true;
|
|
3946
4524
|
}
|
|
3947
4525
|
this.#dirtyColors.clear();
|
|
3948
4526
|
}
|
|
4527
|
+
#paint(colors, ranges, appearance, offset) {
|
|
4528
|
+
if (ranges.length === 0) {
|
|
4529
|
+
return;
|
|
4530
|
+
}
|
|
4531
|
+
writeColor(colors, ranges, appearance, offset);
|
|
4532
|
+
let span = this.#dirtyColors.get(colors);
|
|
4533
|
+
if (!span) {
|
|
4534
|
+
span = { first: Number.POSITIVE_INFINITY, last: 0 };
|
|
4535
|
+
this.#dirtyColors.set(colors, span);
|
|
4536
|
+
}
|
|
4537
|
+
for (const range of ranges) {
|
|
4538
|
+
span.first = Math.min(span.first, range.start);
|
|
4539
|
+
span.last = Math.max(span.last, range.start + range.count - 1);
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
3949
4542
|
};
|
|
3950
4543
|
|
|
3951
4544
|
// src/cubing/twisty/heavy-code-imports/dynamic-entries/twisty-dynamic-3d.ts
|
|
@@ -3954,7 +4547,7 @@ import { Raycaster } from "three/src/core/Raycaster.js";
|
|
|
3954
4547
|
import { TextureLoader as TextureLoader2 } from "three/src/loaders/TextureLoader.js";
|
|
3955
4548
|
import { Spherical } from "three/src/math/Spherical.js";
|
|
3956
4549
|
import { Vector2 as Vector22 } from "three/src/math/Vector2.js";
|
|
3957
|
-
import { Vector3 as
|
|
4550
|
+
import { Vector3 as Vector311 } from "three/src/math/Vector3.js";
|
|
3958
4551
|
import { WebGLRenderer } from "three/src/renderers/WebGLRenderer.js";
|
|
3959
4552
|
import { Scene } from "three/src/scenes/Scene.js";
|
|
3960
4553
|
|
|
@@ -4002,7 +4595,8 @@ async function pg3dShim(renderCallback, puzzleLoader, hintFacelets, faceletScale
|
|
|
4002
4595
|
const plan = darkIgnoredOrbits || pictureCube ? null : cubePuzzlePlan(stickerDat) ?? solidPuzzlePlan(stickerDat);
|
|
4003
4596
|
if (plan) {
|
|
4004
4597
|
return new Stickerless3D(renderCallback, kpuzzle, stickerDat, plan, {
|
|
4005
|
-
hintFacelets
|
|
4598
|
+
hintFacelets,
|
|
4599
|
+
logoFacelet: logoFaceletAddress(puzzleLoader.id, stickerDat)
|
|
4006
4600
|
});
|
|
4007
4601
|
}
|
|
4008
4602
|
return new PG3D(
|
|
@@ -4026,11 +4620,11 @@ export {
|
|
|
4026
4620
|
Spherical as ThreeSpherical,
|
|
4027
4621
|
TextureLoader2 as ThreeTextureLoader,
|
|
4028
4622
|
Vector22 as ThreeVector2,
|
|
4029
|
-
|
|
4623
|
+
Vector311 as ThreeVector3,
|
|
4030
4624
|
WebGLRenderer as ThreeWebGLRenderer,
|
|
4031
4625
|
Twisty3DScene,
|
|
4032
4626
|
cube3DShim,
|
|
4033
4627
|
pg3dShim,
|
|
4034
4628
|
square1_3DShim
|
|
4035
4629
|
};
|
|
4036
|
-
//# sourceMappingURL=twisty-dynamic-3d-
|
|
4630
|
+
//# sourceMappingURL=twisty-dynamic-3d-3MGVD3TG.js.map
|