Skip to content

Commit 69e2c48

Browse files
authored
feat(math)!: Move Quat.toMat4() to Mat4.createRotation() (#930)
1 parent c9009fb commit 69e2c48

File tree

6 files changed

+107
-40
lines changed

6 files changed

+107
-40
lines changed

src/math/Mat4.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,35 @@ export class Mat4 {
449449
]);
450450
}
451451

452+
/**
453+
* @param {import("./Quat.js").QuatParameters} args
454+
*/
455+
static createRotation(...args) {
456+
const q = new Quat(...args);
457+
458+
// https://github.com/toji/gl-matrix/blob/6866ae93d19bbff032139941cbfe0ae68c4cdead/src/gl-matrix/mat4.js#L1186
459+
const x2 = q.x + q.x;
460+
const y2 = q.y + q.y;
461+
const z2 = q.z + q.z;
462+
463+
const xx = q.x * x2;
464+
const yx = q.y * x2;
465+
const yy = q.y * y2;
466+
const zx = q.z * x2;
467+
const zy = q.z * y2;
468+
const zz = q.z * z2;
469+
const wx = q.w * x2;
470+
const wy = q.w * y2;
471+
const wz = q.w * z2;
472+
473+
return new Mat4([
474+
[1 - yy - zz, yx + wz, zx - wy, 0],
475+
[yx - wz, 1 - xx - zz, zy + wx, 0],
476+
[zx + wy, zy - wx, 1 - xx - yy, 0],
477+
[0, 0, 0, 1],
478+
]);
479+
}
480+
452481
/**
453482
* @param {import("./Vec3.js").Vec3Parameters} args
454483
*/

src/math/Quat.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Mat4 } from "./Mat4.js";
21
import { Vec2 } from "./Vec2.js";
32
import { Vec3 } from "./Vec3.js";
43
import { Vec4 } from "./Vec4.js";
@@ -201,30 +200,6 @@ export class Quat {
201200
return vec;
202201
}
203202

204-
toMat4() {
205-
// https://github.com/toji/gl-matrix/blob/6866ae93d19bbff032139941cbfe0ae68c4cdead/src/gl-matrix/mat4.js#L1186
206-
const x2 = this.x + this.x;
207-
const y2 = this.y + this.y;
208-
const z2 = this.z + this.z;
209-
210-
const xx = this.x * x2;
211-
const yx = this.y * x2;
212-
const yy = this.y * y2;
213-
const zx = this.z * x2;
214-
const zy = this.z * y2;
215-
const zz = this.z * z2;
216-
const wx = this.w * x2;
217-
const wy = this.w * y2;
218-
const wz = this.w * z2;
219-
220-
return new Mat4([
221-
[1 - yy - zz, yx + wz, zx - wy, 0],
222-
[yx - wz, 1 - xx - zz, zy + wx, 0],
223-
[zx + wy, zy - wx, 1 - xx - yy, 0],
224-
[0, 0, 0, 1],
225-
]);
226-
}
227-
228203
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
229204
/**
230205
* @param {import("./Vec3.js").Vec3Parameters} args

studio/src/windowManagement/contentWindows/ContentWindowEntityEditor/ContentWindowEntityEditor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ export class ContentWindowEntityEditor extends ContentWindow {
626626
} else if (this.transformationMode == "rotate") {
627627
gizmo = this.gizmos.addGizmo(RotationGizmo);
628628
gizmo.onDrag((e) => {
629-
const localMatrix = e.localDelta.toMat4();
629+
const localMatrix = Mat4.createRotation(e.localDelta);
630630
this.dragSelectedEntities(localMatrix);
631631
});
632632
} else if (this.transformationMode == "scale") {

test/unit/src/math/Mat4.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,36 @@ Deno.test({
205205
},
206206
});
207207

208+
Deno.test({
209+
name: "createTranslation",
210+
fn() {
211+
const mat = Mat4.createTranslation(1, 2, 3);
212+
assertVecAlmostEquals(mat.getTranslation(), [1, 2, 3]);
213+
},
214+
});
215+
216+
Deno.test({
217+
name: "createRotation",
218+
fn() {
219+
const quat = Quat.fromAxisAngle(0, 1, 0, Math.PI * 0.5);
220+
const v1 = Vec3.forward.rotate(quat);
221+
222+
const mat = Mat4.createRotation(quat);
223+
const v2 = new Vec3(0, 0, 1).multiply(mat);
224+
225+
assertVecAlmostEquals(v1, v2);
226+
},
227+
});
228+
229+
Deno.test({
230+
name: "createScale",
231+
fn() {
232+
const mat = Mat4.createScale(1, 2, 3);
233+
234+
assertVecAlmostEquals(mat.getScale(), [1, 2, 3]);
235+
},
236+
});
237+
208238
Deno.test({
209239
name: "multiplyMatrices",
210240
fn() {

test/unit/src/math/Quat.test.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,6 @@ Deno.test({
1717
},
1818
});
1919

20-
Deno.test({
21-
name: "toMat4()",
22-
fn() {
23-
const quat = Quat.fromAxisAngle(0, 1, 0, Math.PI * 0.5);
24-
const v1 = Vec3.forward.rotate(quat);
25-
26-
const mat = quat.toMat4();
27-
const v2 = new Vec3(0, 0, 1).multiply(mat);
28-
29-
assertVecAlmostEquals(v1, v2);
30-
},
31-
});
32-
3320
Deno.test({
3421
name: "toString()",
3522
fn() {

test/unit/studio/src/windowManagement/contentWindows/ContentWindowEntityEditor/transformationGizmos.test.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { basicTest } from "./shared.js";
22
import { ContentWindowEntityEditor } from "../../../../../../../studio/src/windowManagement/contentWindows/ContentWindowEntityEditor/ContentWindowEntityEditor.js";
33
import { assertEquals, assertInstanceOf } from "std/testing/asserts.ts";
4-
import { Entity, Quat, TranslationGizmo, Vec3, assertQuatAlmostEquals, assertVecAlmostEquals } from "../../../../../../../src/mod.js";
4+
import { Entity, Quat, RotationGizmo, TranslationGizmo, Vec3, assertQuatAlmostEquals, assertVecAlmostEquals } from "../../../../../../../src/mod.js";
55
import { stub } from "std/testing/mock.ts";
66

77
function createEntitiesForGizmoTests() {
@@ -203,3 +203,49 @@ Deno.test({
203203
}
204204
},
205205
});
206+
207+
Deno.test({
208+
name: "Dragging a rotation gizmo",
209+
async fn() {
210+
const { args, uninstall } = basicTest();
211+
try {
212+
const contentWindow = new ContentWindowEntityEditor(...args);
213+
contentWindow.setTransformationMode("rotate");
214+
215+
/** @type {import("../../../../../../../src/gizmos/gizmos/RotationGizmo.js").RotationGizmoDragCallback[]} */
216+
const onDragCbs = [];
217+
218+
/** @type {import("std/testing/mock.ts").Stub<import("../../../../../../../src/mod.js").GizmoManager, [...args: any[]], import("../../../../../../../src/mod.js").Gizmo>} */
219+
const addGizmoStub = stub(contentWindow.gizmos, "addGizmo", (...args) => {
220+
const gizmo = addGizmoStub.original.bind(contentWindow.gizmos)(...args);
221+
if (gizmo instanceof RotationGizmo) {
222+
stub(gizmo, "onDrag", (cb) => {
223+
onDragCbs.push(cb);
224+
});
225+
}
226+
return gizmo;
227+
});
228+
229+
const { root } = createEntitiesForGizmoTests();
230+
contentWindow.editingEntity = root;
231+
232+
contentWindow.selectionGroup.changeSelection({
233+
added: [createMockEntitySelection(root)],
234+
});
235+
236+
const gizmos = Array.from(contentWindow.gizmos.gizmos);
237+
assertEquals(gizmos.length, 1);
238+
assertInstanceOf(gizmos[0], RotationGizmo);
239+
240+
assertEquals(onDragCbs.length, 1);
241+
onDragCbs[0]({
242+
localDelta: Quat.fromAxisAngle(0, 1, 0, 0.2),
243+
worldDelta: Quat.fromAxisAngle(0, 1, 0, 0.2),
244+
});
245+
246+
assertQuatAlmostEquals(root.rot, Quat.fromAxisAngle(0, 1, 0, 0.2));
247+
} finally {
248+
uninstall();
249+
}
250+
},
251+
});

0 commit comments

Comments
 (0)