micro-gl 0.1.0
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 +556 -0
- package/package.json +37 -0
- package/src/2d/cameras/Camera2d.js +46 -0
- package/src/2d/constants.js +3 -0
- package/src/2d/controls/DragControls2d.js +174 -0
- package/src/2d/controls/PanZoomControls.js +64 -0
- package/src/2d/core/GpuResources2d.js +163 -0
- package/src/2d/core/InstancedShape2d.js +74 -0
- package/src/2d/core/Object2d.js +107 -0
- package/src/2d/core/Pipelines2d.js +110 -0
- package/src/2d/core/Renderer2d.js +353 -0
- package/src/2d/core/Scene2d.js +13 -0
- package/src/2d/core/Shape2d.js +13 -0
- package/src/2d/core/Uniforms2d.js +13 -0
- package/src/2d/geometries/CircleGeometry.js +27 -0
- package/src/2d/geometries/Geometry2d.js +108 -0
- package/src/2d/geometries/RectGeometry.js +23 -0
- package/src/2d/materials/BasicMaterial2d.js +12 -0
- package/src/2d/materials/Material2d.js +78 -0
- package/src/2d/materials/SpriteMaterial2d.js +28 -0
- package/src/2d/shaders/fragments.js +23 -0
- package/src/2d/shaders/shared.js +28 -0
- package/src/2d/shaders/vertexLayout.js +74 -0
- package/src/2d/shaders/vertexStages.js +59 -0
- package/src/3d/cameras/Camera.js +66 -0
- package/src/3d/cameras/OrthographicCamera.js +35 -0
- package/src/3d/cameras/PerspectiveCamera.js +25 -0
- package/src/3d/constants.js +18 -0
- package/src/3d/controls/DragControls.js +168 -0
- package/src/3d/controls/OrbitControls.js +125 -0
- package/src/3d/core/DirectionalShadowMap.js +283 -0
- package/src/3d/core/GpuResources.js +174 -0
- package/src/3d/core/InstanceMatrix.js +55 -0
- package/src/3d/core/InstancedBounds.js +114 -0
- package/src/3d/core/InstancedMesh.js +124 -0
- package/src/3d/core/Mesh.js +26 -0
- package/src/3d/core/Object3d.js +101 -0
- package/src/3d/core/Pipelines.js +125 -0
- package/src/3d/core/RayIntersection.js +184 -0
- package/src/3d/core/Raycaster.js +246 -0
- package/src/3d/core/Renderer.js +492 -0
- package/src/3d/core/Scene.js +13 -0
- package/src/3d/core/ShadowPipelines.js +64 -0
- package/src/3d/core/Uniforms.js +132 -0
- package/src/3d/geometries/BoxGeometry.js +56 -0
- package/src/3d/geometries/Geometry.js +97 -0
- package/src/3d/geometries/PlaneGeometry.js +24 -0
- package/src/3d/geometries/SphereGeometry.js +46 -0
- package/src/3d/geometries/WireframeGeometry.js +39 -0
- package/src/3d/helpers/GridHelper.js +43 -0
- package/src/3d/lights/AmbientLight.js +18 -0
- package/src/3d/lights/DirectionalLight.js +26 -0
- package/src/3d/lights/DirectionalShadow.js +29 -0
- package/src/3d/lights/PointLight.js +23 -0
- package/src/3d/materials/BasicMaterial.js +11 -0
- package/src/3d/materials/LambertMaterial.js +13 -0
- package/src/3d/materials/Material.js +87 -0
- package/src/3d/materials/TextureMaterial.js +24 -0
- package/src/3d/shaders/fragments.js +34 -0
- package/src/3d/shaders/shadows.js +52 -0
- package/src/3d/shaders/shared.js +129 -0
- package/src/3d/shaders/vertexLayout.js +85 -0
- package/src/3d/shaders/vertexStages.js +70 -0
- package/src/core/PointerControls.js +258 -0
- package/src/core/Texture.js +87 -0
- package/src/core/createMaterialPipelineLayouts.js +114 -0
- package/src/core/deviceLease.js +67 -0
- package/src/core/generateMipmaps.js +115 -0
- package/src/core/indexedTriangles.js +53 -0
- package/src/core/initWebGpu.js +65 -0
- package/src/core/materialResources.js +18 -0
- package/src/core/objectGpuResources.js +68 -0
- package/src/core/pipelineConstants.js +68 -0
- package/src/core/rendererConfig.js +66 -0
- package/src/core/uploadTexture.js +57 -0
- package/src/index.js +68 -0
- package/src/math/Frustum.js +143 -0
- package/src/math/Mat3.js +165 -0
- package/src/math/Mat4.js +359 -0
- package/src/math/Vec2.js +72 -0
- package/src/math/Vec3.js +98 -0
- package/src/math/color.js +20 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// micro-gl — a tiny WebGPU engine, in two flavors that share one canvas:
|
|
2
|
+
// src/3d/ — the perspective engine (Mat4, lights, depth buffer)
|
|
3
|
+
// src/2d/ — the flat engine (Mat3, zIndex ordering, alpha blending)
|
|
4
|
+
// with src/math/ and src/core/ shared between them.
|
|
5
|
+
// Import everything from this single package entry point:
|
|
6
|
+
// import { Renderer, Scene, Mesh, ... } from 'micro-gl';
|
|
7
|
+
|
|
8
|
+
// --- Shared ---------------------------------------------------------------
|
|
9
|
+
export { Vec3 } from './math/Vec3.js';
|
|
10
|
+
export { Mat4 } from './math/Mat4.js';
|
|
11
|
+
export { Frustum } from './math/Frustum.js';
|
|
12
|
+
export { Vec2 } from './math/Vec2.js';
|
|
13
|
+
export { Mat3 } from './math/Mat3.js';
|
|
14
|
+
export { srgbToLinear, linearToSrgb } from './math/color.js';
|
|
15
|
+
export { initWebGpu } from './core/initWebGpu.js';
|
|
16
|
+
export { Texture } from './core/Texture.js';
|
|
17
|
+
export { PointerControls, TOUCH_GESTURE } from './core/PointerControls.js';
|
|
18
|
+
|
|
19
|
+
// --- 3D engine --------------------------------------------------------------
|
|
20
|
+
export { Object3d } from './3d/core/Object3d.js';
|
|
21
|
+
export { Raycaster } from './3d/core/Raycaster.js';
|
|
22
|
+
export { Scene } from './3d/core/Scene.js';
|
|
23
|
+
export { Mesh } from './3d/core/Mesh.js';
|
|
24
|
+
export { InstancedMesh } from './3d/core/InstancedMesh.js';
|
|
25
|
+
export { Renderer } from './3d/core/Renderer.js';
|
|
26
|
+
|
|
27
|
+
export { Camera } from './3d/cameras/Camera.js';
|
|
28
|
+
export { PerspectiveCamera } from './3d/cameras/PerspectiveCamera.js';
|
|
29
|
+
export { OrthographicCamera } from './3d/cameras/OrthographicCamera.js';
|
|
30
|
+
export { OrbitControls } from './3d/controls/OrbitControls.js';
|
|
31
|
+
export { DragControls } from './3d/controls/DragControls.js';
|
|
32
|
+
|
|
33
|
+
export { Geometry } from './3d/geometries/Geometry.js';
|
|
34
|
+
export { BoxGeometry } from './3d/geometries/BoxGeometry.js';
|
|
35
|
+
export { SphereGeometry } from './3d/geometries/SphereGeometry.js';
|
|
36
|
+
export { PlaneGeometry } from './3d/geometries/PlaneGeometry.js';
|
|
37
|
+
export { WireframeGeometry } from './3d/geometries/WireframeGeometry.js';
|
|
38
|
+
|
|
39
|
+
export { Material, MAX_POINT_LIGHTS } from './3d/materials/Material.js';
|
|
40
|
+
export { BasicMaterial } from './3d/materials/BasicMaterial.js';
|
|
41
|
+
export { LambertMaterial } from './3d/materials/LambertMaterial.js';
|
|
42
|
+
export { TextureMaterial } from './3d/materials/TextureMaterial.js';
|
|
43
|
+
|
|
44
|
+
export { DirectionalLight } from './3d/lights/DirectionalLight.js';
|
|
45
|
+
export { DirectionalShadow } from './3d/lights/DirectionalShadow.js';
|
|
46
|
+
export { AmbientLight } from './3d/lights/AmbientLight.js';
|
|
47
|
+
export { PointLight } from './3d/lights/PointLight.js';
|
|
48
|
+
|
|
49
|
+
export { GridHelper } from './3d/helpers/GridHelper.js';
|
|
50
|
+
|
|
51
|
+
// --- 2D engine --------------------------------------------------------------
|
|
52
|
+
export { Object2d } from './2d/core/Object2d.js';
|
|
53
|
+
export { Scene2d } from './2d/core/Scene2d.js';
|
|
54
|
+
export { Shape2d } from './2d/core/Shape2d.js';
|
|
55
|
+
export { InstancedShape2d } from './2d/core/InstancedShape2d.js';
|
|
56
|
+
export { Renderer2d } from './2d/core/Renderer2d.js';
|
|
57
|
+
|
|
58
|
+
export { Camera2d } from './2d/cameras/Camera2d.js';
|
|
59
|
+
export { PanZoomControls } from './2d/controls/PanZoomControls.js';
|
|
60
|
+
export { DragControls2d } from './2d/controls/DragControls2d.js';
|
|
61
|
+
|
|
62
|
+
export { Geometry2d } from './2d/geometries/Geometry2d.js';
|
|
63
|
+
export { RectGeometry } from './2d/geometries/RectGeometry.js';
|
|
64
|
+
export { CircleGeometry } from './2d/geometries/CircleGeometry.js';
|
|
65
|
+
|
|
66
|
+
export { Material2d } from './2d/materials/Material2d.js';
|
|
67
|
+
export { BasicMaterial2d } from './2d/materials/BasicMaterial2d.js';
|
|
68
|
+
export { SpriteMaterial2d } from './2d/materials/SpriteMaterial2d.js';
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const PLANE_COMPONENTS = 4;
|
|
2
|
+
const PLANE_COUNT = 6;
|
|
3
|
+
const PLANE_EPSILON = 1e-12;
|
|
4
|
+
const INTERSECTION_EPSILON = 1e-6;
|
|
5
|
+
const PLANE_INDEX = Object.freeze({
|
|
6
|
+
left: 0,
|
|
7
|
+
right: 1,
|
|
8
|
+
bottom: 2,
|
|
9
|
+
top: 3,
|
|
10
|
+
near: 4,
|
|
11
|
+
far: 5,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const IDENTITY_ELEMENTS = Object.freeze([
|
|
15
|
+
1, 0, 0, 0,
|
|
16
|
+
0, 1, 0, 0,
|
|
17
|
+
0, 0, 1, 0,
|
|
18
|
+
0, 0, 0, 1,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Six clipping planes extracted from a WebGPU view-projection matrix.
|
|
23
|
+
* WebGPU depth is 0..w, so its near plane is `z >= 0` rather than the
|
|
24
|
+
* OpenGL-style `z + w >= 0`.
|
|
25
|
+
*/
|
|
26
|
+
export class Frustum {
|
|
27
|
+
constructor() {
|
|
28
|
+
/** Packed normalized planes: x, y, z, constant. */
|
|
29
|
+
this.planes = new Float32Array(PLANE_COUNT * PLANE_COMPONENTS);
|
|
30
|
+
this.valid = false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Replaces the planes from a column-major view-projection matrix. */
|
|
34
|
+
setFromViewProjectionMatrix(matrix) {
|
|
35
|
+
const e = matrix?.elements;
|
|
36
|
+
if (!e || e.length < 16) {
|
|
37
|
+
this.valid = false;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.valid = true;
|
|
42
|
+
// Clip-space inequalities: x/y in -w..w and z in 0..w.
|
|
43
|
+
this._setPlane(
|
|
44
|
+
PLANE_INDEX.left,
|
|
45
|
+
e[3] + e[0],
|
|
46
|
+
e[7] + e[4],
|
|
47
|
+
e[11] + e[8],
|
|
48
|
+
e[15] + e[12],
|
|
49
|
+
);
|
|
50
|
+
this._setPlane(
|
|
51
|
+
PLANE_INDEX.right,
|
|
52
|
+
e[3] - e[0],
|
|
53
|
+
e[7] - e[4],
|
|
54
|
+
e[11] - e[8],
|
|
55
|
+
e[15] - e[12],
|
|
56
|
+
);
|
|
57
|
+
this._setPlane(
|
|
58
|
+
PLANE_INDEX.bottom,
|
|
59
|
+
e[3] + e[1],
|
|
60
|
+
e[7] + e[5],
|
|
61
|
+
e[11] + e[9],
|
|
62
|
+
e[15] + e[13],
|
|
63
|
+
);
|
|
64
|
+
this._setPlane(
|
|
65
|
+
PLANE_INDEX.top,
|
|
66
|
+
e[3] - e[1],
|
|
67
|
+
e[7] - e[5],
|
|
68
|
+
e[11] - e[9],
|
|
69
|
+
e[15] - e[13],
|
|
70
|
+
);
|
|
71
|
+
this._setPlane(PLANE_INDEX.near, e[2], e[6], e[10], e[14]);
|
|
72
|
+
this._setPlane(
|
|
73
|
+
PLANE_INDEX.far,
|
|
74
|
+
e[3] - e[2],
|
|
75
|
+
e[7] - e[6],
|
|
76
|
+
e[11] - e[10],
|
|
77
|
+
e[15] - e[14],
|
|
78
|
+
);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Tests a local-space axis-aligned box after `transform` is applied.
|
|
84
|
+
* Invalid data fails open (visible) so culling never hides an object merely
|
|
85
|
+
* because a custom matrix or dynamic geometry cannot be bounded safely.
|
|
86
|
+
*/
|
|
87
|
+
intersectsBox(bounds, transform = null) {
|
|
88
|
+
if (!this.valid) return true;
|
|
89
|
+
const min = bounds?.min;
|
|
90
|
+
const max = bounds?.max;
|
|
91
|
+
if (!min || !max || min.length < 3 || max.length < 3) return true;
|
|
92
|
+
|
|
93
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
94
|
+
if (min[axis] > max[axis]) return false;
|
|
95
|
+
if (!Number.isFinite(min[axis]) || !Number.isFinite(max[axis])) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const e = transform?.elements || IDENTITY_ELEMENTS;
|
|
101
|
+
if (e.length < 16) return true;
|
|
102
|
+
for (let i = 0; i < 16; i++) {
|
|
103
|
+
if (!Number.isFinite(e[i])) return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const planes = this.planes;
|
|
107
|
+
for (let offset = 0; offset < planes.length; offset += PLANE_COMPONENTS) {
|
|
108
|
+
const px = planes[offset];
|
|
109
|
+
const py = planes[offset + 1];
|
|
110
|
+
const pz = planes[offset + 2];
|
|
111
|
+
const pw = planes[offset + 3];
|
|
112
|
+
|
|
113
|
+
// Transform the world-space plane into box-local space with M^T. The
|
|
114
|
+
// positive local vertex gives the box's greatest signed plane distance.
|
|
115
|
+
const qx = e[0] * px + e[1] * py + e[2] * pz + e[3] * pw;
|
|
116
|
+
const qy = e[4] * px + e[5] * py + e[6] * pz + e[7] * pw;
|
|
117
|
+
const qz = e[8] * px + e[9] * py + e[10] * pz + e[11] * pw;
|
|
118
|
+
const qw = e[12] * px + e[13] * py + e[14] * pz + e[15] * pw;
|
|
119
|
+
const x = qx >= 0 ? max[0] : min[0];
|
|
120
|
+
const y = qy >= 0 ? max[1] : min[1];
|
|
121
|
+
const z = qz >= 0 ? max[2] : min[2];
|
|
122
|
+
const distance = qx * x + qy * y + qz * z + qw;
|
|
123
|
+
if (!Number.isFinite(distance)) return true;
|
|
124
|
+
if (distance < -INTERSECTION_EPSILON) return false;
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
_setPlane(index, x, y, z, constant) {
|
|
130
|
+
const length = Math.hypot(x, y, z);
|
|
131
|
+
if (!Number.isFinite(length) || length <= PLANE_EPSILON) {
|
|
132
|
+
this.valid = false;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const offset = index * PLANE_COMPONENTS;
|
|
136
|
+
const inverseLength = 1 / length;
|
|
137
|
+
this.planes[offset] = x * inverseLength;
|
|
138
|
+
this.planes[offset + 1] = y * inverseLength;
|
|
139
|
+
this.planes[offset + 2] = z * inverseLength;
|
|
140
|
+
this.planes[offset + 3] = constant * inverseLength;
|
|
141
|
+
if (!Number.isFinite(this.planes[offset + 3])) this.valid = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/math/Mat3.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A 3x3 matrix for 2D affine transforms (translation, rotation, scale).
|
|
3
|
+
*
|
|
4
|
+
* Stored column-major with each column padded to 4 floats — the exact
|
|
5
|
+
* layout WebGPU expects for a `mat3x3f` inside a uniform buffer, so
|
|
6
|
+
* `elements` (12 floats) can be uploaded directly.
|
|
7
|
+
*
|
|
8
|
+
* Logical layout: `elements` indices:
|
|
9
|
+
* | a c tx | | 0 4 8 |
|
|
10
|
+
* | b d ty | | 1 5 9 |
|
|
11
|
+
* | 0 0 1 | | 2 6 10 | (3, 7 and 11 are padding)
|
|
12
|
+
*/
|
|
13
|
+
export class Mat3 {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.elements = new Float32Array(12);
|
|
16
|
+
this.identity();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
identity() {
|
|
20
|
+
const e = this.elements;
|
|
21
|
+
e.fill(0);
|
|
22
|
+
e[0] = e[5] = e[10] = 1;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
copy(m) {
|
|
27
|
+
this.elements.set(m.elements);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** this = this * m */
|
|
32
|
+
multiply(m) {
|
|
33
|
+
return this.multiplyMatrices(this, m);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** this = m * this */
|
|
37
|
+
premultiply(m) {
|
|
38
|
+
return this.multiplyMatrices(m, this);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** this = a * b (safe even when this === a or this === b) */
|
|
42
|
+
multiplyMatrices(a, b) {
|
|
43
|
+
const ae = a.elements;
|
|
44
|
+
const be = b.elements;
|
|
45
|
+
const te = this.elements;
|
|
46
|
+
|
|
47
|
+
const a11 = ae[0],
|
|
48
|
+
a12 = ae[4],
|
|
49
|
+
a13 = ae[8];
|
|
50
|
+
const a21 = ae[1],
|
|
51
|
+
a22 = ae[5],
|
|
52
|
+
a23 = ae[9];
|
|
53
|
+
const a31 = ae[2],
|
|
54
|
+
a32 = ae[6],
|
|
55
|
+
a33 = ae[10];
|
|
56
|
+
|
|
57
|
+
const b11 = be[0],
|
|
58
|
+
b12 = be[4],
|
|
59
|
+
b13 = be[8];
|
|
60
|
+
const b21 = be[1],
|
|
61
|
+
b22 = be[5],
|
|
62
|
+
b23 = be[9];
|
|
63
|
+
const b31 = be[2],
|
|
64
|
+
b32 = be[6],
|
|
65
|
+
b33 = be[10];
|
|
66
|
+
|
|
67
|
+
te[0] = a11 * b11 + a12 * b21 + a13 * b31;
|
|
68
|
+
te[4] = a11 * b12 + a12 * b22 + a13 * b32;
|
|
69
|
+
te[8] = a11 * b13 + a12 * b23 + a13 * b33;
|
|
70
|
+
|
|
71
|
+
te[1] = a21 * b11 + a22 * b21 + a23 * b31;
|
|
72
|
+
te[5] = a21 * b12 + a22 * b22 + a23 * b32;
|
|
73
|
+
te[9] = a21 * b13 + a22 * b23 + a23 * b33;
|
|
74
|
+
|
|
75
|
+
te[2] = a31 * b11 + a32 * b21 + a33 * b31;
|
|
76
|
+
te[6] = a31 * b12 + a32 * b22 + a33 * b32;
|
|
77
|
+
te[10] = a31 * b13 + a32 * b23 + a33 * b33;
|
|
78
|
+
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
makeTranslation(x, y) {
|
|
83
|
+
this.identity();
|
|
84
|
+
const e = this.elements;
|
|
85
|
+
e[8] = x;
|
|
86
|
+
e[9] = y;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
makeRotation(angle) {
|
|
91
|
+
this.identity();
|
|
92
|
+
const c = Math.cos(angle),
|
|
93
|
+
s = Math.sin(angle);
|
|
94
|
+
const e = this.elements;
|
|
95
|
+
e[0] = c;
|
|
96
|
+
e[4] = -s;
|
|
97
|
+
e[1] = s;
|
|
98
|
+
e[5] = c;
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
makeScale(x, y) {
|
|
103
|
+
this.identity();
|
|
104
|
+
const e = this.elements;
|
|
105
|
+
e[0] = x;
|
|
106
|
+
e[5] = y;
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Builds a transform from position, rotation (radians) and scale:
|
|
112
|
+
* this = T * R * S. Small enough in 2D to write out directly.
|
|
113
|
+
*/
|
|
114
|
+
compose(position, rotation, scale) {
|
|
115
|
+
const c = Math.cos(rotation),
|
|
116
|
+
s = Math.sin(rotation);
|
|
117
|
+
const e = this.elements;
|
|
118
|
+
e.fill(0);
|
|
119
|
+
e[0] = c * scale.x;
|
|
120
|
+
e[1] = s * scale.x;
|
|
121
|
+
e[4] = -s * scale.y;
|
|
122
|
+
e[5] = c * scale.y;
|
|
123
|
+
e[8] = position.x;
|
|
124
|
+
e[9] = position.y;
|
|
125
|
+
e[10] = 1;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Inverts the matrix, assuming it is affine (bottom row 0 0 1), and
|
|
131
|
+
* throws when no inverse exists. Every matrix this engine composes is affine.
|
|
132
|
+
*/
|
|
133
|
+
invert() {
|
|
134
|
+
if (!this.tryInvert()) {
|
|
135
|
+
throw new RangeError('Cannot invert a singular Mat3');
|
|
136
|
+
}
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Attempts to invert this affine matrix without changing it when it is
|
|
142
|
+
* singular. Returns whether the inverse was written.
|
|
143
|
+
*/
|
|
144
|
+
tryInvert() {
|
|
145
|
+
const e = this.elements;
|
|
146
|
+
const a = e[0],
|
|
147
|
+
b = e[1],
|
|
148
|
+
c = e[4],
|
|
149
|
+
d = e[5],
|
|
150
|
+
tx = e[8],
|
|
151
|
+
ty = e[9];
|
|
152
|
+
|
|
153
|
+
let det = a * d - b * c;
|
|
154
|
+
if (det === 0 || !Number.isFinite(det)) return false;
|
|
155
|
+
det = 1 / det;
|
|
156
|
+
|
|
157
|
+
e[0] = d * det;
|
|
158
|
+
e[1] = -b * det;
|
|
159
|
+
e[4] = -c * det;
|
|
160
|
+
e[5] = a * det;
|
|
161
|
+
e[8] = (c * ty - d * tx) * det;
|
|
162
|
+
e[9] = (b * tx - a * ty) * det;
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|