1546 lines
52 KiB
JavaScript
1546 lines
52 KiB
JavaScript
import {
|
|
State,
|
|
clamp,
|
|
convertAiaToTurn,
|
|
lerp,
|
|
mod,
|
|
sidesShiftMapper,
|
|
uvsTransformerPresets
|
|
} from "./chunk-YIK32INT.js";
|
|
import {
|
|
Cubie,
|
|
M44,
|
|
Program,
|
|
Quaternion,
|
|
Transform,
|
|
V2,
|
|
V3,
|
|
V4
|
|
} from "./chunk-ROHLD3FA.js";
|
|
import {
|
|
__privateAdd,
|
|
__privateGet,
|
|
__privateMethod,
|
|
__privateSet,
|
|
__publicField
|
|
} from "./chunk-HPRLEMBT.js";
|
|
|
|
// node_modules/rubiks-js/src/ui/camera.js
|
|
var _position, _lookAt, _forward, _right, _up, _fov, _aspect, _width, _height, _near, _far, _projectionMatrix, _worldToCameraMatrix, _projectionMatrixInverse, _cameraToWorldMatrix, _worldProjectionMatrix;
|
|
var Camera = class {
|
|
/**
|
|
* @param {V3} position
|
|
* @param {V3} lookAt
|
|
* @param {V3} up
|
|
* @param {number} fov
|
|
* @param {number} width
|
|
* @param {number} height
|
|
* @param {number} near
|
|
* @param {number} far
|
|
*/
|
|
constructor(position, lookAt, up, fov, width, height, near, far) {
|
|
/** @type {V3} */
|
|
__privateAdd(this, _position);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _lookAt);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _forward);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _right);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _up);
|
|
/** @type {number} */
|
|
__privateAdd(this, _fov);
|
|
/** @type {number} */
|
|
__privateAdd(this, _aspect);
|
|
/** @type {number} */
|
|
__privateAdd(this, _width);
|
|
/** @type {number} */
|
|
__privateAdd(this, _height);
|
|
/** @type {number} */
|
|
__privateAdd(this, _near);
|
|
/** @type {number} */
|
|
__privateAdd(this, _far);
|
|
/** @type {M44} */
|
|
__privateAdd(this, _projectionMatrix);
|
|
/** @type {M44} */
|
|
__privateAdd(this, _worldToCameraMatrix);
|
|
/** @type {M44} */
|
|
__privateAdd(this, _projectionMatrixInverse);
|
|
/** @type {M44} */
|
|
__privateAdd(this, _cameraToWorldMatrix);
|
|
/** @type {M44} */
|
|
__privateAdd(this, _worldProjectionMatrix);
|
|
__privateSet(this, _position, position);
|
|
__privateSet(this, _lookAt, lookAt);
|
|
__privateSet(this, _up, up);
|
|
__privateSet(this, _fov, fov);
|
|
__privateSet(this, _width, width);
|
|
__privateSet(this, _height, height);
|
|
__privateSet(this, _aspect, width / height);
|
|
__privateSet(this, _near, near);
|
|
__privateSet(this, _far, far);
|
|
this.calcCameraDirections();
|
|
this.calcWorldToCameraMatrix();
|
|
this.calcProjectionMatrix();
|
|
}
|
|
/** @param {V3} value */
|
|
set position(value) {
|
|
__privateSet(this, _position, value);
|
|
this.calcCameraDirections();
|
|
this.calcWorldToCameraMatrix();
|
|
}
|
|
/** @param {V3} value */
|
|
set lookAt(value) {
|
|
__privateSet(this, _lookAt, value);
|
|
this.calcCameraDirections();
|
|
this.calcWorldToCameraMatrix();
|
|
}
|
|
/** @param {V3} value */
|
|
set up(value) {
|
|
__privateSet(this, _up, value);
|
|
this.calcCameraDirections();
|
|
this.calcWorldToCameraMatrix();
|
|
}
|
|
get position() {
|
|
return __privateGet(this, _position);
|
|
}
|
|
get lookAt() {
|
|
return __privateGet(this, _lookAt);
|
|
}
|
|
get up() {
|
|
return __privateGet(this, _up);
|
|
}
|
|
get forward() {
|
|
return __privateGet(this, _forward);
|
|
}
|
|
get right() {
|
|
return __privateGet(this, _right);
|
|
}
|
|
/** @param {number} value */
|
|
set fov(value) {
|
|
__privateSet(this, _fov, value);
|
|
this.calcProjectionMatrix();
|
|
}
|
|
/** @param {number} value */
|
|
set near(value) {
|
|
__privateSet(this, _near, value);
|
|
this.calcProjectionMatrix();
|
|
}
|
|
/** @param {number} value */
|
|
set far(value) {
|
|
__privateSet(this, _far, value);
|
|
this.calcProjectionMatrix();
|
|
}
|
|
get fov() {
|
|
return __privateGet(this, _fov);
|
|
}
|
|
get aspect() {
|
|
return __privateGet(this, _aspect);
|
|
}
|
|
get near() {
|
|
return __privateGet(this, _near);
|
|
}
|
|
get far() {
|
|
return __privateGet(this, _far);
|
|
}
|
|
get width() {
|
|
return __privateGet(this, _width);
|
|
}
|
|
get height() {
|
|
return __privateGet(this, _height);
|
|
}
|
|
/**
|
|
* @param {number} width
|
|
* @param {number} height
|
|
*/
|
|
screenSize(width, height) {
|
|
__privateSet(this, _width, width);
|
|
__privateSet(this, _height, height);
|
|
__privateSet(this, _aspect, width / height);
|
|
this.calcProjectionMatrix();
|
|
}
|
|
get projectionMatrix() {
|
|
return __privateGet(this, _projectionMatrix);
|
|
}
|
|
get projectionMatrixInverse() {
|
|
return __privateGet(this, _projectionMatrixInverse);
|
|
}
|
|
get worldToCameraMatrix() {
|
|
return __privateGet(this, _worldToCameraMatrix);
|
|
}
|
|
get cameraToWorldMatrix() {
|
|
return __privateGet(this, _cameraToWorldMatrix);
|
|
}
|
|
get worldProjectionMatrix() {
|
|
return __privateGet(this, _worldProjectionMatrix);
|
|
}
|
|
/** @param {V3} v */
|
|
worldToScreen({ x, y, z }) {
|
|
const point4d = this.worldProjectionMatrix.mult(new V4(x, y, z, 1));
|
|
const screenPoint = point4d.toV3().scale(1 / point4d.w).toV2().add(new V2(1, 1)).scale(0.5).mult(new V2(this.width, this.height));
|
|
return screenPoint;
|
|
}
|
|
// worldDirectionToScreen({x, y, z}: V3) {
|
|
// // const rotationTransform = this.cameraToWorldMatrix.transpose
|
|
// const cameraPoint = this.worldToCameraMatrix.mult(new V4(x, y, z, 1))
|
|
// const projectedPoint = this.projectionMatrix.mult(cameraPoint)
|
|
// const viewportPoint = projectedPoint.toV3().scale(1 / projectedPoint.w).toV2()
|
|
// const screenPoint = viewportPoint.add(new V2(1, 1)).scale(.5).mult(new V2(this.width, this.height))
|
|
// // console.log(this.projectionMatrix)
|
|
// console.table({cameraPoint, projectedPoint, viewportPoint, screenPoint})
|
|
// return screenPoint
|
|
// }
|
|
calcProjectionMatrix() {
|
|
var _a3;
|
|
__privateSet(this, _projectionMatrix, M44.perspective(__privateGet(this, _fov) * Math.PI / 180, __privateGet(this, _aspect), __privateGet(this, _near), __privateGet(this, _far)));
|
|
__privateSet(this, _projectionMatrixInverse, __privateGet(this, _projectionMatrix).inverse);
|
|
__privateSet(this, _worldProjectionMatrix, (_a3 = __privateGet(this, _projectionMatrix)) == null ? void 0 : _a3.mult(__privateGet(this, _worldToCameraMatrix)));
|
|
}
|
|
calcWorldToCameraMatrix() {
|
|
var _a3;
|
|
__privateSet(this, _worldToCameraMatrix, M44.lookAt(__privateGet(this, _position), __privateGet(this, _lookAt), __privateGet(this, _up)));
|
|
__privateSet(this, _cameraToWorldMatrix, __privateGet(this, _worldToCameraMatrix).inverse);
|
|
__privateSet(this, _worldProjectionMatrix, (_a3 = __privateGet(this, _projectionMatrix)) == null ? void 0 : _a3.mult(__privateGet(this, _worldToCameraMatrix)));
|
|
}
|
|
calcCameraDirections() {
|
|
__privateSet(this, _forward, __privateGet(this, _lookAt).sub(__privateGet(this, _position)).normalized);
|
|
__privateSet(this, _right, __privateGet(this, _up).cross(__privateGet(this, _forward)).normalized);
|
|
}
|
|
};
|
|
_position = new WeakMap();
|
|
_lookAt = new WeakMap();
|
|
_forward = new WeakMap();
|
|
_right = new WeakMap();
|
|
_up = new WeakMap();
|
|
_fov = new WeakMap();
|
|
_aspect = new WeakMap();
|
|
_width = new WeakMap();
|
|
_height = new WeakMap();
|
|
_near = new WeakMap();
|
|
_far = new WeakMap();
|
|
_projectionMatrix = new WeakMap();
|
|
_worldToCameraMatrix = new WeakMap();
|
|
_projectionMatrixInverse = new WeakMap();
|
|
_cameraToWorldMatrix = new WeakMap();
|
|
_worldProjectionMatrix = new WeakMap();
|
|
|
|
// node_modules/rubiks-js/src/ui/rubiks.js
|
|
var rotationAxis = [
|
|
V3.getRotationAxis(0),
|
|
V3.getRotationAxis(1),
|
|
V3.getRotationAxis(2)
|
|
];
|
|
var cubeRotationOnMiddle = {
|
|
0: {
|
|
2: 90,
|
|
3: -90,
|
|
4: -90,
|
|
5: 90
|
|
},
|
|
1: {
|
|
0: -90,
|
|
1: 90,
|
|
4: 90,
|
|
5: -90
|
|
},
|
|
2: {
|
|
0: 90,
|
|
1: -90,
|
|
2: -90,
|
|
3: 90
|
|
}
|
|
};
|
|
var uvsTransformers = {
|
|
0: {
|
|
0: uvsTransformerPresets.rcR2Rcc,
|
|
1: uvsTransformerPresets.rcR2Rcc,
|
|
2: uvsTransformerPresets.flipV23,
|
|
3: uvsTransformerPresets.flipV23,
|
|
4: uvsTransformerPresets.flipV12,
|
|
5: uvsTransformerPresets.flipV12
|
|
},
|
|
1: {
|
|
0: uvsTransformerPresets.rcfhFvRcc,
|
|
1: uvsTransformerPresets.rcfhFvRcc,
|
|
2: uvsTransformerPresets.rcR2Rcc,
|
|
3: uvsTransformerPresets.rcR2Rcc,
|
|
4: uvsTransformerPresets.rcFhRcfh,
|
|
5: uvsTransformerPresets.rcFhRcfh
|
|
},
|
|
2: {
|
|
0: uvsTransformerPresets.flipH23,
|
|
1: uvsTransformerPresets.flipH23,
|
|
2: uvsTransformerPresets.flipH12,
|
|
3: uvsTransformerPresets.flipH12,
|
|
4: uvsTransformerPresets.rcR2Rcc,
|
|
5: uvsTransformerPresets.rcR2Rcc
|
|
}
|
|
};
|
|
var shouldInvertAngle = (axis, side) => {
|
|
return side === 0 || side === 2 && axis === 0 || side === 3 && axis === 2 || side === 5;
|
|
};
|
|
var RubiksTransform = class extends Transform {
|
|
/**
|
|
* @param {V3} position
|
|
* @param {Quaternion} rotation
|
|
*/
|
|
constructor(position, rotation) {
|
|
super(position, rotation, null);
|
|
/** @type {[V3, V3, V3]} */
|
|
__publicField(this, "rotationAxis");
|
|
this.setTransforms();
|
|
}
|
|
/** @property */
|
|
setTransforms() {
|
|
super.setTransforms();
|
|
this.rotationAxis = /** @type {[V3, V3, V3]} */
|
|
rotationAxis.map((axis) => {
|
|
return this.apply(axis);
|
|
});
|
|
}
|
|
};
|
|
var _turnCallback, _axisDeltasMap, _Rubiks_instances, turn_fn, swapOuterFacelets_fn, swapInnerFacelets_fn, _rotatingCubies, _rotationAxis, _rotationCenter, _currentAngle, _initialAngle, _rotatingAutomatic, _turnProgress, _turnSpeed, _targetAngle, _rotationIndex, _rotationAxisIndex, _side;
|
|
var _Rubiks = class _Rubiks {
|
|
/**
|
|
* @param {Quaternion} rotation
|
|
* @param {number[][][]} uvs
|
|
* @param {V3[]} hoveringColors
|
|
* @param {TurnCallback} turnCallback
|
|
*/
|
|
constructor(rotation, uvs, hoveringColors, turnCallback) {
|
|
__privateAdd(this, _Rubiks_instances);
|
|
/** @type {RubiksTransform} */
|
|
__publicField(this, "transform");
|
|
/** @type {Cubie[]} */
|
|
__publicField(this, "cubies");
|
|
/** @type {TurnCallback} */
|
|
__privateAdd(this, _turnCallback);
|
|
// manual rotation
|
|
/** @type {Array<{cubie: Cubie, backupPosition: V3, backupRotation: Quaternion, directionFromCenter: V3}>} */
|
|
__privateAdd(this, _rotatingCubies, []);
|
|
__privateAdd(this, _rotationAxis, V3.zero);
|
|
__privateAdd(this, _rotationCenter, V3.zero);
|
|
__privateAdd(this, _currentAngle, 0);
|
|
// automatic rotation
|
|
__privateAdd(this, _initialAngle, 0);
|
|
__privateAdd(this, _rotatingAutomatic, false);
|
|
__privateAdd(this, _turnProgress, 0);
|
|
__privateAdd(this, _turnSpeed, 4);
|
|
__privateAdd(this, _targetAngle, 0);
|
|
__privateAdd(this, _rotationIndex, 0);
|
|
__privateAdd(this, _rotationAxisIndex, 0);
|
|
__privateAdd(this, _side, 0);
|
|
__privateSet(this, _turnCallback, turnCallback);
|
|
this.transform = new RubiksTransform(V3.zero, rotation);
|
|
this.cubies = [];
|
|
for (let i = 0; i < 27; i++) {
|
|
const cubie = new Cubie(
|
|
i,
|
|
uvs,
|
|
hoveringColors,
|
|
this
|
|
);
|
|
this.cubies.push(cubie);
|
|
this.transform.children.push(cubie);
|
|
}
|
|
}
|
|
/**
|
|
* @param {import('./program').Program} program
|
|
* @param {WebGL2RenderingContext} gl
|
|
* @param {WebGLBuffer} uvsVbo
|
|
*/
|
|
render(program, gl, uvsVbo) {
|
|
this.cubies.forEach((cubie) => cubie.render(program, gl, uvsVbo));
|
|
}
|
|
/**
|
|
* @param {number} axis
|
|
* @param {number} index
|
|
* @returns {Cubie[]}
|
|
*/
|
|
getPlane(axis, index) {
|
|
const [d1, d2] = __privateGet(_Rubiks, _axisDeltasMap)[axis];
|
|
const initial = Math.pow(3, axis) * index;
|
|
const cubies = [];
|
|
for (let i = 0; i < 3; i++) {
|
|
for (let j = 0; j < 3; j++) {
|
|
const index2 = initial + i * d1 + j * d2;
|
|
const cubie = this.cubies[index2];
|
|
cubies.push(cubie);
|
|
}
|
|
}
|
|
return cubies;
|
|
}
|
|
/**
|
|
* @param {Cubie[]} cubies
|
|
* @param {V3} axis
|
|
*/
|
|
startRotation(cubies, axis) {
|
|
__privateSet(this, _rotationAxis, axis);
|
|
__privateSet(this, _rotationCenter, cubies[4].transform.position);
|
|
__privateSet(this, _rotatingCubies, cubies.map((cubie) => {
|
|
return {
|
|
cubie,
|
|
backupPosition: cubie.transform.position,
|
|
backupRotation: cubie.transform.rotation,
|
|
directionFromCenter: cubie.transform.position.sub(__privateGet(this, _rotationCenter))
|
|
};
|
|
}));
|
|
}
|
|
/** @param {number} angle */
|
|
rotateManual(angle) {
|
|
const rotation = Quaternion.fromAngle(__privateGet(this, _rotationAxis), -angle);
|
|
__privateSet(this, _currentAngle, angle);
|
|
__privateGet(this, _rotatingCubies).forEach(({ cubie, backupRotation, directionFromCenter }) => {
|
|
const rotatedDirectionFromCenter = rotation.rotate(directionFromCenter);
|
|
const newPosition = __privateGet(this, _rotationCenter).add(rotatedDirectionFromCenter);
|
|
cubie.transform.position = newPosition;
|
|
cubie.transform.rotation = backupRotation;
|
|
cubie.transform.rotate(__privateGet(this, _rotationAxis), angle);
|
|
});
|
|
}
|
|
/**
|
|
* @param {number} axis
|
|
* @param {number} index
|
|
* @param {number} angle
|
|
* @param {number} side
|
|
*/
|
|
finishRotation(axis, index, angle, side) {
|
|
__privateSet(this, _rotatingAutomatic, true);
|
|
__privateSet(this, _turnProgress, 0);
|
|
__privateSet(this, _targetAngle, angle);
|
|
__privateSet(this, _initialAngle, __privateGet(this, _currentAngle));
|
|
__privateSet(this, _rotationIndex, index);
|
|
__privateSet(this, _rotationAxisIndex, axis);
|
|
__privateSet(this, _side, side);
|
|
}
|
|
/** @param {number} delta */
|
|
update(delta) {
|
|
if (!__privateGet(this, _rotatingAutomatic)) {
|
|
return;
|
|
}
|
|
__privateSet(this, _turnProgress, __privateGet(this, _turnProgress) + delta * __privateGet(this, _turnSpeed));
|
|
if (__privateGet(this, _turnProgress) >= 1) {
|
|
__privateSet(this, _rotatingAutomatic, false);
|
|
__privateGet(this, _rotatingCubies).forEach(({ cubie, backupPosition, backupRotation }) => {
|
|
cubie.transform.position = backupPosition;
|
|
cubie.transform.rotation = backupRotation;
|
|
});
|
|
__privateMethod(this, _Rubiks_instances, turn_fn).call(this, __privateGet(this, _rotationAxisIndex), __privateGet(this, _rotationIndex), __privateGet(this, _targetAngle), __privateGet(this, _side), __privateGet(this, _rotatingCubies).map(({ cubie }) => cubie));
|
|
return;
|
|
}
|
|
const currentAngle = lerp(__privateGet(this, _initialAngle), __privateGet(this, _targetAngle) * 90, __privateGet(this, _turnProgress));
|
|
const rotation = Quaternion.fromAngle(__privateGet(this, _rotationAxis), -currentAngle);
|
|
__privateGet(this, _rotatingCubies).forEach(({ cubie, backupRotation, directionFromCenter }) => {
|
|
cubie.transform.rotation = backupRotation.mult(Quaternion.fromAngle(__privateGet(this, _rotationAxis), currentAngle));
|
|
const rotatedDirectionFromCenter = rotation.rotate(directionFromCenter);
|
|
const newPosition = __privateGet(this, _rotationCenter).add(rotatedDirectionFromCenter);
|
|
cubie.transform.position = newPosition;
|
|
});
|
|
}
|
|
get isTurning() {
|
|
return __privateGet(this, _rotatingAutomatic);
|
|
}
|
|
};
|
|
_turnCallback = new WeakMap();
|
|
_axisDeltasMap = new WeakMap();
|
|
_Rubiks_instances = new WeakSet();
|
|
/**
|
|
* @param {number} axis
|
|
* @param {number} index
|
|
* @param {number} angle
|
|
* @param {number} side
|
|
* @param {Cubie[]} plane
|
|
*/
|
|
turn_fn = function(axis, index, angle, side, plane) {
|
|
angle = mod(angle, 4);
|
|
if (angle === 0) {
|
|
return;
|
|
}
|
|
if (index === 1) {
|
|
__privateMethod(this, _Rubiks_instances, turn_fn).call(this, axis, 0, -angle, side, this.getPlane(axis, 0));
|
|
__privateMethod(this, _Rubiks_instances, turn_fn).call(this, axis, 2, -angle, side, this.getPlane(axis, 2));
|
|
this.transform.rotate(this.transform.rotationAxis[axis], angle * cubeRotationOnMiddle[axis][side]);
|
|
return;
|
|
}
|
|
if (shouldInvertAngle(axis, side)) {
|
|
angle = mod(-angle, 4);
|
|
}
|
|
__privateMethod(this, _Rubiks_instances, swapOuterFacelets_fn).call(this, plane, axis, angle);
|
|
__privateMethod(this, _Rubiks_instances, swapInnerFacelets_fn).call(this, plane, axis, index, angle);
|
|
__privateGet(this, _turnCallback).call(this, { axis, index, angle });
|
|
};
|
|
/**
|
|
* @param {Cubie[]} plane
|
|
* @param {number} axis
|
|
* @param {number} angle
|
|
*/
|
|
swapOuterFacelets_fn = function(plane, axis, angle) {
|
|
const [s0, s1, s2, s3] = sidesShiftMapper[axis];
|
|
const facelets = [
|
|
plane[0].getFaceletOfSide(s0),
|
|
plane[1].getFaceletOfSide(s0),
|
|
plane[2].getFaceletOfSide(s0),
|
|
plane[2].getFaceletOfSide(s1),
|
|
plane[5].getFaceletOfSide(s1),
|
|
plane[8].getFaceletOfSide(s1),
|
|
plane[8].getFaceletOfSide(s2),
|
|
plane[7].getFaceletOfSide(s2),
|
|
plane[6].getFaceletOfSide(s2),
|
|
plane[6].getFaceletOfSide(s3),
|
|
plane[3].getFaceletOfSide(s3),
|
|
plane[0].getFaceletOfSide(s3)
|
|
];
|
|
const shiftedUvs = [];
|
|
for (let index = 0; index < 12; index++) {
|
|
const shiftedIndex = mod(index + 3 * angle, 12);
|
|
const { uvs } = facelets[shiftedIndex];
|
|
const facelet = facelets[index];
|
|
const transformer = uvsTransformers[axis][facelet.side][angle];
|
|
shiftedUvs[index] = transformer(uvs);
|
|
}
|
|
for (let index = 0; index < 12; index++) {
|
|
facelets[index].uvs = shiftedUvs[index];
|
|
}
|
|
};
|
|
/**
|
|
* @param {Cubie[]} plane
|
|
* @param {number} axis
|
|
* @param {number} index
|
|
* @param {number} angle
|
|
*/
|
|
swapInnerFacelets_fn = function(plane, axis, index, angle) {
|
|
const side = axis * 2 + Math.sign(index);
|
|
const facelets = [
|
|
plane[0].getFaceletOfSide(side),
|
|
plane[1].getFaceletOfSide(side),
|
|
plane[2].getFaceletOfSide(side),
|
|
plane[5].getFaceletOfSide(side),
|
|
plane[8].getFaceletOfSide(side),
|
|
plane[7].getFaceletOfSide(side),
|
|
plane[6].getFaceletOfSide(side),
|
|
plane[3].getFaceletOfSide(side)
|
|
];
|
|
const shiftedUvs = [];
|
|
const transformer = uvsTransformers[axis][side][angle];
|
|
for (let index2 = 0; index2 < 8; index2++) {
|
|
const shiftedIndex = mod(index2 + 2 * angle, 8);
|
|
const { uvs } = facelets[shiftedIndex];
|
|
shiftedUvs[index2] = transformer(uvs);
|
|
}
|
|
for (let index2 = 0; index2 < 8; index2++) {
|
|
facelets[index2].uvs = shiftedUvs[index2];
|
|
}
|
|
const center = plane[4].getFaceletOfSide(side);
|
|
center.uvs = transformer(center.uvs);
|
|
};
|
|
_rotatingCubies = new WeakMap();
|
|
_rotationAxis = new WeakMap();
|
|
_rotationCenter = new WeakMap();
|
|
_currentAngle = new WeakMap();
|
|
_initialAngle = new WeakMap();
|
|
_rotatingAutomatic = new WeakMap();
|
|
_turnProgress = new WeakMap();
|
|
_turnSpeed = new WeakMap();
|
|
_targetAngle = new WeakMap();
|
|
_rotationIndex = new WeakMap();
|
|
_rotationAxisIndex = new WeakMap();
|
|
_side = new WeakMap();
|
|
/** @type {[number, number][]} */
|
|
__privateAdd(_Rubiks, _axisDeltasMap, [
|
|
[3, 9],
|
|
[1, 9],
|
|
[1, 3]
|
|
]);
|
|
var Rubiks = _Rubiks;
|
|
|
|
// node_modules/rubiks-js/src/ui/ray.js
|
|
var _origin, _direction, _Ray_instances, intersectCube_fn;
|
|
var Ray = class {
|
|
/**
|
|
* @param {import('./camera').Camera} camera
|
|
* @param {number} x
|
|
* @param {number} y
|
|
* @param {number} width
|
|
* @param {number} height
|
|
*/
|
|
constructor(camera, x, y, width, height) {
|
|
__privateAdd(this, _Ray_instances);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _origin);
|
|
/** @type {V3} */
|
|
__privateAdd(this, _direction);
|
|
const u = (x + 0.5) / width * 2 - 1;
|
|
const v = (height - y + 0.5) / height * 2 - 1;
|
|
__privateSet(this, _origin, camera.cameraToWorldMatrix.mult(new V4(0, 0, 0, 1)).toV3());
|
|
const d1 = camera.projectionMatrixInverse.mult(new V4(u, v, 0, 1));
|
|
const d2 = camera.cameraToWorldMatrix.mult(new V4(d1.x, d1.y, d1.z, 0));
|
|
__privateSet(this, _direction, d2.toV3().normalized);
|
|
}
|
|
/** @param {import('./rubiks').Rubiks} rubiks */
|
|
intersectRubiks(rubiks) {
|
|
return rubiks.cubies.map((cubie) => __privateMethod(this, _Ray_instances, intersectCube_fn).call(this, cubie)).flat(1);
|
|
}
|
|
/**
|
|
* @param {import('./facelet').Facelet} facelet
|
|
* @returns {{
|
|
* inside: false
|
|
* } | {
|
|
* inside: true,
|
|
* facelet: import('./facelet').Facelet,
|
|
* d: number
|
|
* }}
|
|
*/
|
|
intersectFacelet(facelet) {
|
|
const { normal, top, left, topLeft, bottomRight } = facelet.transform;
|
|
const denom = __privateGet(this, _direction).dot(normal);
|
|
if (denom === 0) {
|
|
return { inside: false };
|
|
}
|
|
const d = topLeft.sub(__privateGet(this, _origin)).dot(normal) / denom;
|
|
const intersection = __privateGet(this, _origin).add(__privateGet(this, _direction).scale(d));
|
|
const fromTopLeft = intersection.sub(topLeft).normalized;
|
|
const fromBottomRight = intersection.sub(bottomRight).normalized;
|
|
const dot1 = fromTopLeft.dot(left);
|
|
const dot2 = fromTopLeft.dot(top);
|
|
const dot3 = fromBottomRight.dot(left.negate);
|
|
const dot4 = fromBottomRight.dot(top.negate);
|
|
const inside = dot1 <= 1 && dot1 >= 0 && dot2 <= 1 && dot2 >= 0 && dot3 <= 1 && dot3 >= 0 && dot4 <= 1 && dot4 >= 0;
|
|
if (!inside) {
|
|
return { inside: false };
|
|
}
|
|
return {
|
|
inside,
|
|
facelet,
|
|
d
|
|
};
|
|
}
|
|
};
|
|
_origin = new WeakMap();
|
|
_direction = new WeakMap();
|
|
_Ray_instances = new WeakSet();
|
|
/** @param {import('./cubie').Cubie} cubie */
|
|
intersectCube_fn = function(cubie) {
|
|
return cubie.facelets.reduce((acc, facelet) => {
|
|
const hit = this.intersectFacelet(facelet);
|
|
if (hit.inside) {
|
|
acc.push({ facelet: hit.facelet, d: hit.d });
|
|
}
|
|
return acc;
|
|
}, []);
|
|
};
|
|
|
|
// node_modules/rubiks-js/src/ui/inputHandler.js
|
|
var _a, _b, _c, _d, _e, _canvas, _rubiks, _camera, _maxZoom, _minZoom, _pointers, _action, _InputHandler_instances, setAction_fn, _pointerDown, _InputHandler_static, getPointerDown_fn, _pointerMove, getPointerMove_fn, _pointerUp, getPointerUp_fn, _pointerLeave, getPointerLeave_fn, _wheel, getWheel_fn, startActionRotatingSide_fn, actionRotatingSide_fn, startActionRotatingCube_fn, actionRotatingCube_fn, startActionGesture_fn, actionGesture_fn, actionHovering_fn, getTurnDirection_fn, rotateSide_fn, rotateCube_fn, zoomCube_fn, getZoom_fn;
|
|
var _InputHandler = class _InputHandler {
|
|
/**
|
|
* @param {HTMLCanvasElement} canvas
|
|
* @param {import('./rubiks').Rubiks} rubiks
|
|
* @param {import('./camera').Camera} camera
|
|
*/
|
|
constructor(canvas, rubiks, camera) {
|
|
__privateAdd(this, _InputHandler_instances);
|
|
/** @type {HTMLCanvasElement} */
|
|
__privateAdd(this, _canvas);
|
|
/** @type {import('./rubiks').Rubiks} */
|
|
__privateAdd(this, _rubiks);
|
|
/** @type {import('./camera').Camera} */
|
|
__privateAdd(this, _camera);
|
|
/** @readonly */
|
|
__privateAdd(this, _maxZoom, 40);
|
|
/** @readonly */
|
|
__privateAdd(this, _minZoom, 10);
|
|
/** @type {Map<number, PointerEvent>} */
|
|
__privateAdd(this, _pointers, /* @__PURE__ */ new Map());
|
|
/** @type {import('../types').Action} */
|
|
__privateAdd(this, _action, { type: "none" });
|
|
// event handlers
|
|
__privateAdd(this, _pointerDown, __privateMethod(_a = _InputHandler, _InputHandler_static, getPointerDown_fn).call(_a, this));
|
|
__privateAdd(this, _pointerMove, __privateMethod(_b = _InputHandler, _InputHandler_static, getPointerMove_fn).call(_b, this));
|
|
__privateAdd(this, _pointerUp, __privateMethod(_c = _InputHandler, _InputHandler_static, getPointerUp_fn).call(_c, this));
|
|
__privateAdd(this, _pointerLeave, __privateMethod(_d = _InputHandler, _InputHandler_static, getPointerLeave_fn).call(_d, this));
|
|
__privateAdd(this, _wheel, __privateMethod(_e = _InputHandler, _InputHandler_static, getWheel_fn).call(_e, this));
|
|
__privateSet(this, _canvas, canvas);
|
|
__privateSet(this, _rubiks, rubiks);
|
|
__privateSet(this, _camera, camera);
|
|
}
|
|
addEventListeners() {
|
|
__privateGet(this, _canvas).addEventListener("pointermove", __privateGet(this, _pointerMove));
|
|
__privateGet(this, _canvas).addEventListener("pointerdown", __privateGet(this, _pointerDown));
|
|
__privateGet(this, _canvas).addEventListener("pointerup", __privateGet(this, _pointerUp));
|
|
__privateGet(this, _canvas).addEventListener("pointerleave", __privateGet(this, _pointerLeave));
|
|
__privateGet(this, _canvas).addEventListener("wheel", __privateGet(this, _wheel));
|
|
}
|
|
removeEventListeners() {
|
|
__privateGet(this, _canvas).removeEventListener("pointermove", __privateGet(this, _pointerMove));
|
|
__privateGet(this, _canvas).removeEventListener("pointerdown", __privateGet(this, _pointerDown));
|
|
__privateGet(this, _canvas).removeEventListener("pointerup", __privateGet(this, _pointerUp));
|
|
__privateGet(this, _canvas).removeEventListener("pointerleave", __privateGet(this, _pointerLeave));
|
|
__privateGet(this, _canvas).removeEventListener("wheel", __privateGet(this, _wheel));
|
|
}
|
|
};
|
|
_canvas = new WeakMap();
|
|
_rubiks = new WeakMap();
|
|
_camera = new WeakMap();
|
|
_maxZoom = new WeakMap();
|
|
_minZoom = new WeakMap();
|
|
_pointers = new WeakMap();
|
|
_action = new WeakMap();
|
|
_InputHandler_instances = new WeakSet();
|
|
/** @param {import('../types').Action} action */
|
|
setAction_fn = function(action) {
|
|
if (__privateGet(this, _action).type === "hovering") {
|
|
__privateGet(this, _action).facelet.hovering = false;
|
|
}
|
|
if (action.type === "hovering") {
|
|
action.facelet.hovering = true;
|
|
}
|
|
if (__privateGet(this, _action).type === "rotatingSide" && __privateGet(this, _action).side) {
|
|
const info = __privateGet(this, _action)[__privateGet(this, _action).side];
|
|
const angle = Math.round(info.angle / 90);
|
|
__privateGet(this, _rubiks).finishRotation(info.axis, info.index, angle, __privateGet(this, _action).facelet.side);
|
|
}
|
|
__privateSet(this, _action, action);
|
|
};
|
|
_pointerDown = new WeakMap();
|
|
_InputHandler_static = new WeakSet();
|
|
getPointerDown_fn = function(inputHandler) {
|
|
return (event) => {
|
|
var _a3, _b2, _c2, _d2, _e2;
|
|
const { offsetX, offsetY, pointerId } = event;
|
|
if (event.button === 0) {
|
|
__privateGet(inputHandler, _pointers).set(pointerId, event);
|
|
} else if (event.button === 1) {
|
|
__privateGet(inputHandler, _pointers).set(pointerId, event);
|
|
__privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
|
|
type: "rotatingCube",
|
|
mouse: new V2(offsetX, offsetY)
|
|
});
|
|
return;
|
|
}
|
|
if (__privateGet(inputHandler, _pointers).size === 1) {
|
|
if (__privateGet(inputHandler, _rubiks).isTurning) {
|
|
return;
|
|
}
|
|
if (__privateGet(inputHandler, _action).type === "none") {
|
|
__privateMethod(_b2 = inputHandler, _InputHandler_instances, actionHovering_fn).call(_b2, offsetX, offsetY);
|
|
}
|
|
if (__privateGet(inputHandler, _action).type === "hovering") {
|
|
__privateMethod(_c2 = inputHandler, _InputHandler_instances, startActionRotatingSide_fn).call(_c2, offsetX, offsetY, __privateGet(inputHandler, _action).facelet);
|
|
return;
|
|
}
|
|
__privateMethod(_d2 = inputHandler, _InputHandler_instances, startActionRotatingCube_fn).call(_d2, offsetX, offsetY);
|
|
} else if (__privateGet(inputHandler, _pointers).size === 2) {
|
|
__privateMethod(_e2 = inputHandler, _InputHandler_instances, startActionGesture_fn).call(_e2);
|
|
}
|
|
};
|
|
};
|
|
_pointerMove = new WeakMap();
|
|
getPointerMove_fn = function(inputHandler) {
|
|
return (event) => {
|
|
var _a3, _b2, _c2, _d2;
|
|
const { offsetX, offsetY } = event;
|
|
if (__privateGet(inputHandler, _pointers).size === 0) {
|
|
__privateMethod(_a3 = inputHandler, _InputHandler_instances, actionHovering_fn).call(_a3, offsetX, offsetY);
|
|
return;
|
|
}
|
|
__privateGet(inputHandler, _pointers).set(event.pointerId, event);
|
|
__privateMethod(_b2 = inputHandler, _InputHandler_instances, actionRotatingSide_fn).call(_b2, offsetX, offsetY);
|
|
__privateMethod(_c2 = inputHandler, _InputHandler_instances, actionRotatingCube_fn).call(_c2, offsetX, offsetY);
|
|
__privateMethod(_d2 = inputHandler, _InputHandler_instances, actionGesture_fn).call(_d2);
|
|
};
|
|
};
|
|
_pointerUp = new WeakMap();
|
|
getPointerUp_fn = function(inputHandler) {
|
|
return () => {
|
|
var _a3;
|
|
__privateGet(inputHandler, _pointers).clear();
|
|
__privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
|
|
type: "none"
|
|
});
|
|
};
|
|
};
|
|
_pointerLeave = new WeakMap();
|
|
getPointerLeave_fn = function(inputHandler) {
|
|
return () => {
|
|
var _a3;
|
|
__privateGet(inputHandler, _pointers).clear();
|
|
__privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
|
|
type: "none"
|
|
});
|
|
};
|
|
};
|
|
_wheel = new WeakMap();
|
|
getWheel_fn = function(inputHandler) {
|
|
return ({ deltaY, deltaMode }) => {
|
|
var _a3;
|
|
if (deltaMode !== WheelEvent.DOM_DELTA_PIXEL) {
|
|
return;
|
|
}
|
|
const d = clamp(deltaY / 102, -1, 1) * 0.1;
|
|
__privateMethod(_a3 = inputHandler, _InputHandler_instances, zoomCube_fn).call(_a3, d);
|
|
};
|
|
};
|
|
// actions
|
|
// rotating side
|
|
/**
|
|
* @param {number} offsetX
|
|
* @param {number} offsetY
|
|
* @param {import('./facelet').Facelet} hovering
|
|
*/
|
|
startActionRotatingSide_fn = function(offsetX, offsetY, hovering) {
|
|
const { left, top, topLeft } = hovering.transform;
|
|
const screenTopLeft = __privateGet(this, _camera).worldToScreen(topLeft);
|
|
const screenBottomLeft = __privateGet(this, _camera).worldToScreen(topLeft.add(left));
|
|
const screenTopRight = __privateGet(this, _camera).worldToScreen(topLeft.add(top));
|
|
const rightDir = screenTopRight.sub(screenTopLeft).normalized;
|
|
const downDir = screenBottomLeft.sub(screenTopLeft).normalized;
|
|
const rubiksRotation = __privateGet(this, _rubiks).transform;
|
|
const side = hovering.side;
|
|
const currentAxis = Math.floor(side / 2);
|
|
const cubie = hovering.transform.parent;
|
|
const [axis1, axis2] = [0, 1, 2].filter((axis) => axis !== currentAxis).map((axis) => {
|
|
const rotationAxis2 = V3.getRotationAxis(axis);
|
|
const rubiksRotationAxis = rubiksRotation.apply(rotationAxis2);
|
|
const index = Math.floor(cubie.index / Math.pow(3, axis)) % 3;
|
|
const info = {
|
|
default: rubiksRotationAxis,
|
|
inverted: rubiksRotationAxis.negate,
|
|
axis,
|
|
index
|
|
};
|
|
return info;
|
|
});
|
|
const sideInvertMap = [
|
|
false,
|
|
true,
|
|
true,
|
|
false,
|
|
false,
|
|
true
|
|
];
|
|
const invert = sideInvertMap[hovering.side];
|
|
const mouse = new V2(offsetX, __privateGet(this, _canvas).height - offsetY);
|
|
if (Math.abs(axis1.default.dot(top)) > 0.99) {
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "rotatingSide",
|
|
mouse,
|
|
down: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis1, top, downDir, true !== invert),
|
|
right: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis2, left, rightDir, false !== invert),
|
|
side: null,
|
|
facelet: hovering
|
|
});
|
|
} else {
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "rotatingSide",
|
|
mouse,
|
|
down: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis2, top, downDir, true !== invert),
|
|
right: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis1, left, rightDir, false !== invert),
|
|
side: null,
|
|
facelet: hovering
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* @param {number} offsetX
|
|
* @param {number} offsetY
|
|
*/
|
|
actionRotatingSide_fn = function(offsetX, offsetY) {
|
|
if (__privateGet(this, _action).type !== "rotatingSide") {
|
|
return;
|
|
}
|
|
const mouse = new V2(offsetX, __privateGet(this, _canvas).height - offsetY);
|
|
if (__privateGet(this, _action).mouse.sub(mouse).mag < 10) {
|
|
return;
|
|
}
|
|
const initialMouse = __privateGet(this, _action).mouse;
|
|
if (__privateGet(this, _action).side) {
|
|
__privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, __privateGet(this, _action)[__privateGet(this, _action).side], initialMouse);
|
|
return;
|
|
}
|
|
const { right, down } = __privateGet(this, _action);
|
|
const mouseDir = mouse.sub(initialMouse).normalized;
|
|
const rightDot = right.dir.dot(mouseDir);
|
|
const downDot = down.dir.dot(mouseDir);
|
|
if (Math.abs(rightDot) > Math.abs(downDot)) {
|
|
__privateGet(this, _action).side = "right";
|
|
__privateGet(this, _rubiks).startRotation(right.cubies, right.rotationAxis);
|
|
__privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, right, initialMouse);
|
|
} else {
|
|
__privateGet(this, _action).side = "down";
|
|
__privateGet(this, _rubiks).startRotation(down.cubies, down.rotationAxis);
|
|
__privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, down, initialMouse);
|
|
}
|
|
};
|
|
// rotating cube
|
|
/**
|
|
* @param {number} offsetX
|
|
* @param {number} offsetY
|
|
*/
|
|
startActionRotatingCube_fn = function(offsetX, offsetY) {
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "rotatingCube",
|
|
mouse: new V2(offsetX, offsetY)
|
|
});
|
|
};
|
|
/**
|
|
* @param {number} offsetX
|
|
* @param {number} offsetY
|
|
*/
|
|
actionRotatingCube_fn = function(offsetX, offsetY) {
|
|
if (__privateGet(this, _action).type !== "rotatingCube") {
|
|
return;
|
|
}
|
|
const mouse = new V2(offsetX, offsetY);
|
|
const delta = mouse.sub(__privateGet(this, _action).mouse);
|
|
__privateGet(this, _action).mouse = mouse;
|
|
__privateMethod(this, _InputHandler_instances, rotateCube_fn).call(this, delta);
|
|
};
|
|
// two pointer gesture
|
|
startActionGesture_fn = function() {
|
|
const [e1, e2] = __privateGet(this, _pointers).values();
|
|
const dx = e1.screenX - e2.screenX;
|
|
const dy = e1.screenY - e2.screenY;
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "gesture",
|
|
distance: dx * dx + dy * dy,
|
|
center: new V2(e1.screenX + e2.screenX, e1.screenY + e2.screenY).scale(0.5)
|
|
});
|
|
};
|
|
actionGesture_fn = function() {
|
|
if (__privateGet(this, _action).type !== "gesture") {
|
|
return;
|
|
}
|
|
const [e1, e2] = __privateGet(this, _pointers).values();
|
|
const dx = e1.screenX - e2.screenX;
|
|
const dy = e1.screenY - e2.screenY;
|
|
const distance = dx * dx + dy * dy;
|
|
const deltaDistance = distance - __privateGet(this, _action).distance;
|
|
__privateGet(this, _action).distance = distance;
|
|
const d = clamp(deltaDistance / 1e3, -1, 1) * -0.02;
|
|
__privateMethod(this, _InputHandler_instances, zoomCube_fn).call(this, d);
|
|
const center = new V2(e1.screenX + e2.screenX, e1.screenY + e2.screenY).scale(0.5);
|
|
const deltaCenter = center.sub(__privateGet(this, _action).center);
|
|
__privateGet(this, _action).center = center;
|
|
__privateMethod(this, _InputHandler_instances, rotateCube_fn).call(this, deltaCenter);
|
|
};
|
|
// hovering
|
|
/**
|
|
* @param {number} offsetX
|
|
* @param {number} offsetY
|
|
*/
|
|
actionHovering_fn = function(offsetX, offsetY) {
|
|
const ray = new Ray(__privateGet(this, _camera), offsetX, offsetY, window.innerWidth, window.innerHeight);
|
|
const facelets = ray.intersectRubiks(__privateGet(this, _rubiks));
|
|
if (facelets.length) {
|
|
facelets.sort((a, b) => a.d - b.d);
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "hovering",
|
|
facelet: facelets[0].facelet
|
|
});
|
|
} else {
|
|
__privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
|
|
type: "none"
|
|
});
|
|
}
|
|
};
|
|
// action helpers
|
|
// rotating side
|
|
/**
|
|
* @param {import('../types').AxisInfo} axisInfo
|
|
* @param {V3} vector
|
|
* @param {V2} dir
|
|
* @param {boolean} invert
|
|
* @returns {import('../types').SideInfo}
|
|
*/
|
|
getTurnDirection_fn = function(axisInfo, vector, dir, invert) {
|
|
if (axisInfo.default.dot(vector) > 0.99)
|
|
return {
|
|
dir,
|
|
angle: 0,
|
|
axis: axisInfo.axis,
|
|
rotationAxis: V3.getRotationAxis(axisInfo.axis).scale(invert ? -1 : 1),
|
|
index: axisInfo.index,
|
|
cubies: __privateGet(this, _rubiks).getPlane(axisInfo.axis, axisInfo.index)
|
|
};
|
|
return {
|
|
dir,
|
|
angle: 0,
|
|
axis: axisInfo.axis,
|
|
rotationAxis: V3.getRotationAxis(axisInfo.axis).scale(invert ? 1 : -1),
|
|
index: axisInfo.index,
|
|
cubies: __privateGet(this, _rubiks).getPlane(axisInfo.axis, axisInfo.index)
|
|
};
|
|
};
|
|
/**
|
|
* @param {V2} mouse
|
|
* @param {import('../types').SideInfo} info
|
|
* @param {V2} initialMouse
|
|
*/
|
|
rotateSide_fn = function(mouse, info, initialMouse) {
|
|
const length = info.dir.dot(initialMouse.sub(mouse));
|
|
const zoom = __privateMethod(this, _InputHandler_instances, getZoom_fn).call(this);
|
|
info.angle = length / (3 - zoom * 2);
|
|
__privateGet(this, _rubiks).rotateManual(info.angle);
|
|
};
|
|
// rotating cube
|
|
/** @param {V2} delta */
|
|
rotateCube_fn = function(delta) {
|
|
if (delta.x === 0 && delta.y === 0) {
|
|
return;
|
|
}
|
|
const n = __privateGet(this, _camera).up.scale(delta.y).add(__privateGet(this, _camera).right.scale(delta.x));
|
|
const axis = __privateGet(this, _camera).forward.cross(n);
|
|
const zoom = __privateMethod(this, _InputHandler_instances, getZoom_fn).call(this);
|
|
const angle = Math.sqrt(delta.x * delta.x + delta.y * delta.y) * 0.3 + 2 * zoom;
|
|
__privateGet(this, _rubiks).transform.rotate(axis, angle);
|
|
};
|
|
// zooming camera
|
|
/** @param {number} d */
|
|
zoomCube_fn = function(d) {
|
|
const { position } = __privateGet(this, _camera);
|
|
__privateGet(this, _camera).position = new V3(0, 0, clamp(position.z * (1 + d), -__privateGet(this, _maxZoom), -__privateGet(this, _minZoom)));
|
|
};
|
|
getZoom_fn = function() {
|
|
const zoom = -__privateGet(this, _camera).position.z;
|
|
const minZoom = __privateGet(this, _minZoom);
|
|
const maxZoom = __privateGet(this, _maxZoom);
|
|
return (zoom - minZoom) / (maxZoom - minZoom);
|
|
};
|
|
__privateAdd(_InputHandler, _InputHandler_static);
|
|
var InputHandler = _InputHandler;
|
|
|
|
// node_modules/rubiks-js/src/ui/debugger.js
|
|
var _ctx, _canvas2, _strokeColor, _fillColor, _Debugger_static, flipVector_fn;
|
|
var _Debugger = class _Debugger {
|
|
/**
|
|
* @param {Element?} canvas
|
|
*/
|
|
constructor(canvas) {
|
|
/** @type {CanvasRenderingContext2D?} */
|
|
__privateAdd(this, _ctx);
|
|
/** @type {HTMLCanvasElement?} */
|
|
__privateAdd(this, _canvas2);
|
|
__privateAdd(this, _strokeColor, "white");
|
|
__privateAdd(this, _fillColor, "white");
|
|
if (!canvas) {
|
|
return;
|
|
}
|
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
|
throw new Error(`rubiks cube debugger is not a canvas, it is a <${canvas.tagName}>`);
|
|
}
|
|
__privateSet(this, _canvas2, canvas);
|
|
const ctx = canvas.getContext("2d");
|
|
if (!ctx)
|
|
throw new Error("cannot create 2d context for rubiks cube debugger");
|
|
__privateSet(this, _ctx, ctx);
|
|
}
|
|
clear() {
|
|
if (__privateGet(this, _ctx) && __privateGet(this, _canvas2)) {
|
|
__privateGet(this, _ctx).clearRect(0, 0, __privateGet(this, _canvas2).width, __privateGet(this, _canvas2).height);
|
|
}
|
|
}
|
|
/** @param {string} color */
|
|
stroke(color) {
|
|
__privateSet(this, _strokeColor, color);
|
|
}
|
|
/** @param {string} color */
|
|
fill(color) {
|
|
__privateSet(this, _fillColor, color);
|
|
}
|
|
/**
|
|
* @param {V2} from
|
|
* @param {V2} to
|
|
*/
|
|
line(from, to) {
|
|
var _a3, _b2;
|
|
if (__privateGet(this, _ctx) && __privateGet(this, _canvas2)) {
|
|
__privateGet(this, _ctx).strokeStyle = __privateGet(this, _strokeColor);
|
|
__privateGet(this, _ctx).lineWidth = 3;
|
|
const fromF = __privateMethod(_a3 = _Debugger, _Debugger_static, flipVector_fn).call(_a3, from, __privateGet(this, _canvas2));
|
|
const toF = __privateMethod(_b2 = _Debugger, _Debugger_static, flipVector_fn).call(_b2, to, __privateGet(this, _canvas2));
|
|
__privateGet(this, _ctx).beginPath();
|
|
__privateGet(this, _ctx).moveTo(fromF.x, fromF.y);
|
|
__privateGet(this, _ctx).lineTo(toF.x, toF.y);
|
|
__privateGet(this, _ctx).stroke();
|
|
}
|
|
}
|
|
/**
|
|
* @param {V2} origin
|
|
* @param {V2} direction
|
|
* @param {number} [length=1]
|
|
*/
|
|
vector(origin, direction, length = 1) {
|
|
this.line(origin, origin.add(direction.scale(length)));
|
|
}
|
|
/**
|
|
* @param {number} width
|
|
* @param {number} height
|
|
*/
|
|
setSize(width, height) {
|
|
if (__privateGet(this, _canvas2)) {
|
|
__privateGet(this, _canvas2).width = width;
|
|
__privateGet(this, _canvas2).height = height;
|
|
}
|
|
}
|
|
/**
|
|
* @param {V2} pos
|
|
* @param {string} text
|
|
*/
|
|
text(pos, text) {
|
|
if (__privateGet(this, _ctx)) {
|
|
__privateGet(this, _ctx).fillStyle = __privateGet(this, _fillColor);
|
|
__privateGet(this, _ctx).fillText(text, pos.x, pos.y);
|
|
}
|
|
}
|
|
};
|
|
_ctx = new WeakMap();
|
|
_canvas2 = new WeakMap();
|
|
_strokeColor = new WeakMap();
|
|
_fillColor = new WeakMap();
|
|
_Debugger_static = new WeakSet();
|
|
flipVector_fn = function({ x, y }, canvas) {
|
|
return new V2(x, canvas.height - y);
|
|
};
|
|
__privateAdd(_Debugger, _Debugger_static);
|
|
var Debugger = _Debugger;
|
|
var debugger_default = new Debugger(document.querySelector("[data-rubiks-cube-debug]"));
|
|
|
|
// node_modules/rubiks-js/src/shaders/facelet.glsl.js
|
|
var vertex = `#version 300 es
|
|
|
|
layout (location = 0) in vec3 aPos;
|
|
layout (location = 1) in vec2 aUV;
|
|
|
|
out vec2 uv;
|
|
out vec2 pos;
|
|
|
|
uniform mat4 model;
|
|
uniform mat4 view;
|
|
uniform mat4 projection;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
|
uv = aUV;
|
|
pos = aPos.yz;
|
|
}`;
|
|
var fragment = `#version 300 es
|
|
|
|
precision mediump float;
|
|
|
|
in vec2 uv;
|
|
in vec2 pos;
|
|
|
|
out vec4 FragColor;
|
|
|
|
uniform sampler2D tex;
|
|
uniform vec3 colorMult;
|
|
|
|
vec3 rime = vec3(0.07);
|
|
float outer = 0.45;
|
|
float inner = 0.44;
|
|
|
|
float map(float value, float min1, float max1, float min2, float max2)
|
|
{
|
|
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
float x = abs(pos.x);
|
|
float y = abs(pos.y);
|
|
if (x > outer || y > outer) {
|
|
FragColor = vec4(rime, 1.0);
|
|
return;
|
|
}
|
|
vec3 color = texture(tex, uv).rgb * colorMult;
|
|
if (x > inner || y > inner) {
|
|
float t = smoothstep(0.0, 1.0, map(max(x, y), outer, inner, 0.0, 1.0));
|
|
vec3 c = color * t + rime * (1.0 - t);
|
|
FragColor = vec4(c, 1.0);
|
|
return;
|
|
}
|
|
FragColor = vec4(color, 1.0);
|
|
}`;
|
|
|
|
// node_modules/rubiks-js/src/events.js
|
|
var ChangeEvent = class {
|
|
/**
|
|
* @param {number} axis
|
|
* @param {number} index
|
|
* @param {number} angle
|
|
* @param {import('./state/types').Turn} turn
|
|
* @param {import('./state').StateInfo} state
|
|
*/
|
|
constructor(axis, index, angle, turn, state) {
|
|
/**
|
|
* Axis that was turned around
|
|
*
|
|
* 0 => x-axis (from right to left)
|
|
*
|
|
* 1 => y-axis (from bottom to top)
|
|
*
|
|
* 2 => z-axis (from front to back)
|
|
* @type {0 | 1 | 2}
|
|
*/
|
|
__publicField(this, "axis");
|
|
/**
|
|
* The slice on the axis. Example using axis = 0:
|
|
*
|
|
* 0 => Left slice
|
|
*
|
|
* 2 => Right slice
|
|
*
|
|
* The middle layer is never turned. Instead both outer layers are turn
|
|
* in the opposite direction. This has the same effect.
|
|
* That way the centers always stay in the same position.
|
|
* @type {0 | 2}
|
|
*/
|
|
__publicField(this, "index");
|
|
/**
|
|
* Important: The angle is always clockwise around the axis and not
|
|
* clockwise around the turning side. This means that R and L' both
|
|
* have an angle of 1
|
|
* @type {1 | 2 | 3}
|
|
*/
|
|
__publicField(this, "angle");
|
|
/**
|
|
* @type {import('./state/types').Turn}
|
|
*/
|
|
__publicField(this, "turn");
|
|
/**
|
|
* @type {import('./state').StateInfo}
|
|
*/
|
|
__publicField(this, "state");
|
|
this.axis = /** @type {0 | 1 | 2} */
|
|
axis;
|
|
this.index = /** @type {0 | 2} */
|
|
index;
|
|
this.angle = /** @type {1 | 2 | 3} */
|
|
angle;
|
|
this.turn = turn;
|
|
this.state = state;
|
|
}
|
|
};
|
|
|
|
// node_modules/rubiks-js/src/rubiksCube.js
|
|
var _a2, _initialized, _gl, _canvas3, _program, _vao, _uvsVbo, _texture, _camera2, _rubiks2, _inputHandler, _state, _trackCenters, _frame, _resizeHandler, _canvasData, _image, _uvs, _hoveringColors, _RubiksCube_static, getResizeHandler_fn, _RubiksCube_instances, initialize_fn, _listeners, turnHandler_fn;
|
|
var _RubiksCube = class _RubiksCube {
|
|
/**
|
|
* @param {string} canvasData
|
|
* @param {ImageData | HTMLImageElement} image
|
|
* @param {number[][][]} uvs
|
|
* @param {number[][]} hoveringColors
|
|
* @param {boolean} trackCenters
|
|
*/
|
|
constructor(canvasData, image, uvs, hoveringColors, trackCenters) {
|
|
__privateAdd(this, _RubiksCube_instances);
|
|
__privateAdd(this, _initialized, false);
|
|
/** @type {WebGL2RenderingContext} */
|
|
__privateAdd(this, _gl);
|
|
/** @type {HTMLCanvasElement} */
|
|
__privateAdd(this, _canvas3);
|
|
/** @type {Program} */
|
|
__privateAdd(this, _program);
|
|
/** @type {WebGLVertexArrayObject} */
|
|
__privateAdd(this, _vao);
|
|
/** @type {WebGLBuffer} */
|
|
__privateAdd(this, _uvsVbo);
|
|
/** @type {WebGLTexture} */
|
|
__privateAdd(this, _texture);
|
|
/** @type {Camera} */
|
|
__privateAdd(this, _camera2);
|
|
/** @type {Rubiks} */
|
|
__privateAdd(this, _rubiks2);
|
|
/** @type {InputHandler} */
|
|
__privateAdd(this, _inputHandler);
|
|
/** @type {State} */
|
|
__privateAdd(this, _state);
|
|
/** @type {boolean} */
|
|
__privateAdd(this, _trackCenters);
|
|
__privateAdd(this, _frame, 0);
|
|
__privateAdd(this, _resizeHandler, __privateMethod(_a2 = _RubiksCube, _RubiksCube_static, getResizeHandler_fn).call(_a2, this));
|
|
/** @type {string} */
|
|
__privateAdd(this, _canvasData);
|
|
/** @type {ImageData | HTMLImageElement} */
|
|
__privateAdd(this, _image);
|
|
/** @type {number[][][]} */
|
|
__privateAdd(this, _uvs);
|
|
/** @type {number[][]} */
|
|
__privateAdd(this, _hoveringColors);
|
|
/** @type {Map<keyof Events, Set<(event: any) => void>>} */
|
|
__privateAdd(this, _listeners, /* @__PURE__ */ new Map());
|
|
__privateSet(this, _canvasData, canvasData);
|
|
__privateSet(this, _image, image);
|
|
__privateSet(this, _uvs, uvs);
|
|
__privateSet(this, _hoveringColors, hoveringColors);
|
|
__privateSet(this, _trackCenters, trackCenters);
|
|
}
|
|
/**
|
|
* Starts rendering the cube and listening for user inputs.
|
|
* Automaticly initializes webgl and pointer event listeners.
|
|
*/
|
|
start() {
|
|
if (!__privateGet(this, _initialized)) {
|
|
__privateMethod(this, _RubiksCube_instances, initialize_fn).call(this);
|
|
__privateSet(this, _initialized, true);
|
|
}
|
|
__privateGet(this, _inputHandler).addEventListeners();
|
|
window.addEventListener("resize", __privateGet(this, _resizeHandler));
|
|
__privateGet(this, _resizeHandler).call(this);
|
|
__privateGet(this, _program).use();
|
|
__privateGet(this, _gl).bindVertexArray(__privateGet(this, _vao));
|
|
__privateGet(this, _gl).activeTexture(__privateGet(this, _gl).TEXTURE0);
|
|
__privateGet(this, _gl).bindTexture(__privateGet(this, _gl).TEXTURE_2D, __privateGet(this, _texture));
|
|
__privateGet(this, _program).uniform("tex", {
|
|
setUniform: (gl, location) => gl.uniform1i(location, 0)
|
|
});
|
|
let lastTime = Date.now();
|
|
const loop = () => {
|
|
const currentTime = Date.now();
|
|
const deltaTime = (currentTime - lastTime) / 1e3;
|
|
lastTime = currentTime;
|
|
__privateGet(this, _gl).clear(__privateGet(this, _gl).COLOR_BUFFER_BIT | __privateGet(this, _gl).DEPTH_BUFFER_BIT);
|
|
__privateGet(this, _program).uniform("view", __privateGet(this, _camera2).worldToCameraMatrix);
|
|
__privateGet(this, _program).uniform("projection", __privateGet(this, _camera2).projectionMatrix);
|
|
__privateGet(this, _rubiks2).render(__privateGet(this, _program), __privateGet(this, _gl), __privateGet(this, _uvsVbo));
|
|
__privateGet(this, _rubiks2).update(deltaTime);
|
|
__privateSet(this, _frame, requestAnimationFrame(loop));
|
|
};
|
|
__privateSet(this, _frame, requestAnimationFrame(loop));
|
|
}
|
|
/**
|
|
* Stops rendering the cube and removes all listeners.
|
|
*/
|
|
stop() {
|
|
window.removeEventListener("resize", __privateGet(this, _resizeHandler));
|
|
cancelAnimationFrame(__privateGet(this, _frame));
|
|
__privateGet(this, _inputHandler).removeEventListeners();
|
|
}
|
|
/**
|
|
* Resets the internal state and applys it to the cube.
|
|
*/
|
|
reset() {
|
|
__privateGet(this, _state).reset();
|
|
__privateGet(this, _state).applyState(__privateGet(this, _uvs), __privateGet(this, _rubiks2));
|
|
}
|
|
/**
|
|
* @param {string} stateStr a base46 representation
|
|
* @returns {boolean} false if `stateStr` was invalid
|
|
*/
|
|
setState(stateStr) {
|
|
if (!__privateGet(this, _initialized)) {
|
|
__privateMethod(this, _RubiksCube_instances, initialize_fn).call(this);
|
|
__privateSet(this, _initialized, true);
|
|
}
|
|
if (!__privateGet(this, _state).decode(stateStr)) {
|
|
return false;
|
|
}
|
|
__privateGet(this, _state).applyState(__privateGet(this, _uvs), __privateGet(this, _rubiks2));
|
|
return true;
|
|
}
|
|
get transform() {
|
|
return __privateGet(this, _rubiks2).transform;
|
|
}
|
|
/**
|
|
* @template {keyof Events} Name
|
|
* @param {Name} name
|
|
* @param {(event: Events[Name]) => void} callback
|
|
*/
|
|
on(name, callback) {
|
|
const set = __privateGet(this, _listeners).get(name) ?? /* @__PURE__ */ new Set();
|
|
set.add(callback);
|
|
__privateGet(this, _listeners).set(name, set);
|
|
}
|
|
};
|
|
_initialized = new WeakMap();
|
|
_gl = new WeakMap();
|
|
_canvas3 = new WeakMap();
|
|
_program = new WeakMap();
|
|
_vao = new WeakMap();
|
|
_uvsVbo = new WeakMap();
|
|
_texture = new WeakMap();
|
|
_camera2 = new WeakMap();
|
|
_rubiks2 = new WeakMap();
|
|
_inputHandler = new WeakMap();
|
|
_state = new WeakMap();
|
|
_trackCenters = new WeakMap();
|
|
_frame = new WeakMap();
|
|
_resizeHandler = new WeakMap();
|
|
_canvasData = new WeakMap();
|
|
_image = new WeakMap();
|
|
_uvs = new WeakMap();
|
|
_hoveringColors = new WeakMap();
|
|
_RubiksCube_static = new WeakSet();
|
|
getResizeHandler_fn = function(rubiksCube) {
|
|
return () => {
|
|
const width = window.innerWidth;
|
|
const height = window.innerHeight;
|
|
debugger_default.setSize(width, height);
|
|
__privateGet(rubiksCube, _canvas3).width = width;
|
|
__privateGet(rubiksCube, _canvas3).height = height;
|
|
__privateGet(rubiksCube, _gl).viewport(0, 0, width, height);
|
|
__privateGet(rubiksCube, _camera2).screenSize(width, height);
|
|
};
|
|
};
|
|
_RubiksCube_instances = new WeakSet();
|
|
initialize_fn = function() {
|
|
const canvas = document.querySelector(`[${__privateGet(this, _canvasData)}]`);
|
|
if (!canvas) {
|
|
throw new Error(`<canvas ${__privateGet(this, _canvasData)}> does not exist`);
|
|
}
|
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
|
throw new Error(`<canvas ${__privateGet(this, _canvasData)}> is not a canvas, it is a <${canvas.tagName}>`);
|
|
}
|
|
__privateSet(this, _canvas3, canvas);
|
|
const gl = canvas.getContext("webgl2");
|
|
if (!gl) {
|
|
throw new Error(`cannot create webgl2 context`);
|
|
}
|
|
__privateSet(this, _gl, gl);
|
|
gl.enable(gl.DEPTH_TEST);
|
|
gl.depthFunc(gl.LESS);
|
|
__privateSet(this, _program, new Program("rubiksCube/shaders/facelet.glsl", vertex, fragment, gl));
|
|
const vao = gl.createVertexArray();
|
|
if (!vao) {
|
|
throw new Error("could not create a webgl vertex array object");
|
|
}
|
|
__privateSet(this, _vao, vao);
|
|
gl.bindVertexArray(vao);
|
|
const vertices = [
|
|
0,
|
|
-0.5,
|
|
-0.5,
|
|
0,
|
|
-0.5,
|
|
0.5,
|
|
0,
|
|
0.5,
|
|
0.5,
|
|
0,
|
|
0.5,
|
|
-0.5
|
|
];
|
|
const verticesBuffer = new Float32Array(vertices);
|
|
const verticesVbo = gl.createBuffer();
|
|
const indices = [
|
|
0,
|
|
1,
|
|
3,
|
|
1,
|
|
3,
|
|
2
|
|
];
|
|
const indicesBuffer = new Int8Array(indices);
|
|
const ebo = gl.createBuffer();
|
|
const uvsVbo = gl.createBuffer();
|
|
if (!verticesVbo || !ebo || !uvsVbo) {
|
|
throw new Error("could not create a vertex buffer objects");
|
|
}
|
|
__privateSet(this, _uvsVbo, uvsVbo);
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer, gl.STATIC_DRAW);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, verticesVbo);
|
|
gl.bufferData(gl.ARRAY_BUFFER, verticesBuffer, gl.STATIC_DRAW);
|
|
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 12, 0);
|
|
gl.enableVertexAttribArray(0);
|
|
gl.enableVertexAttribArray(1);
|
|
gl.bindVertexArray(null);
|
|
const texture = gl.createTexture();
|
|
if (!texture) {
|
|
throw new Error("could not create a texture");
|
|
}
|
|
__privateSet(this, _texture, texture);
|
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
gl.texImage2D(
|
|
gl.TEXTURE_2D,
|
|
0,
|
|
gl.RGBA,
|
|
gl.RGBA,
|
|
gl.UNSIGNED_BYTE,
|
|
__privateGet(this, _image)
|
|
);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
const hoveringColors = __privateGet(this, _hoveringColors).map(([r, g, b]) => new V3(r, g, b));
|
|
__privateSet(this, _camera2, new Camera(new V3(0, 0, -10), V3.zero, V3.up, 45, window.innerWidth, window.innerHeight, 0.1, 100));
|
|
__privateSet(this, _rubiks2, new Rubiks(Quaternion.identity, __privateGet(this, _uvs), hoveringColors, __privateMethod(this, _RubiksCube_instances, turnHandler_fn).bind(this)));
|
|
__privateSet(this, _inputHandler, new InputHandler(canvas, __privateGet(this, _rubiks2), __privateGet(this, _camera2)));
|
|
__privateSet(this, _state, new State(__privateGet(this, _trackCenters)));
|
|
};
|
|
_listeners = new WeakMap();
|
|
/**
|
|
* @param {import('./types').AIA} aia
|
|
*/
|
|
turnHandler_fn = function(aia) {
|
|
const turn = convertAiaToTurn(aia);
|
|
__privateGet(this, _state).applyTurn(turn);
|
|
const changeHandlers = __privateGet(this, _listeners).get("change");
|
|
if (changeHandlers) {
|
|
const event = new ChangeEvent(
|
|
aia.axis,
|
|
aia.index,
|
|
aia.angle,
|
|
turn,
|
|
__privateGet(this, _state).stateInfo
|
|
);
|
|
for (const callback of changeHandlers) {
|
|
callback(event);
|
|
}
|
|
}
|
|
};
|
|
__privateAdd(_RubiksCube, _RubiksCube_static);
|
|
var RubiksCube = _RubiksCube;
|
|
|
|
// node_modules/rubiks-js/src/index.js
|
|
var defaultTexture = new ImageData(new Uint8ClampedArray([
|
|
0,
|
|
0,
|
|
255,
|
|
255,
|
|
0,
|
|
255,
|
|
0,
|
|
255,
|
|
255,
|
|
255,
|
|
0,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
0,
|
|
0,
|
|
255,
|
|
255,
|
|
127,
|
|
0,
|
|
255
|
|
]), 1, 6);
|
|
var defaultUVs = Array(6).fill(null).map((_, index) => {
|
|
return Array(9).fill([
|
|
0,
|
|
(index + 0) / 6,
|
|
1,
|
|
(index + 0) / 6,
|
|
1,
|
|
(index + 1) / 6,
|
|
0,
|
|
(index + 1) / 6
|
|
]);
|
|
});
|
|
var defaultHovorvingColors = Array(6).fill(Array(3).fill(0.7));
|
|
export {
|
|
RubiksCube,
|
|
defaultHovorvingColors,
|
|
defaultTexture,
|
|
defaultUVs
|
|
};
|
|
//# sourceMappingURL=rubiks-js.js.map
|