HumanBreak/src/core/render/transform.ts

225 lines
5.5 KiB
TypeScript
Raw Normal View History

import { mat3, ReadonlyMat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix';
2024-05-09 23:49:53 +08:00
export class Transform {
2024-05-09 23:49:53 +08:00
mat: mat3 = mat3.create();
x: number = 0;
y: number = 0;
scaleX: number = 1;
scaleY: number = 1;
rad: number = 0;
/** 有没有对这个Transform进行过修改用于优化常规表现 */
private modified: boolean = false;
2024-05-16 22:43:24 +08:00
2024-05-09 23:49:53 +08:00
/**
*
2024-05-09 23:49:53 +08:00
*/
reset() {
mat3.identity(this.mat);
this.x = 0;
this.y = 0;
this.scaleX = 1;
this.scaleY = 1;
this.rad = 0;
this.modified = false;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
scale(x: number, y: number = x) {
mat3.scale(this.mat, this.mat, [x, y]);
this.scaleX *= x;
this.scaleY *= y;
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
move(x: number, y: number) {
2024-05-10 17:33:27 +08:00
mat3.translate(this.mat, this.mat, [-x, -y]);
2024-05-09 23:49:53 +08:00
this.x += x;
this.y += y;
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
rotate(rad: number) {
mat3.rotate(this.mat, this.mat, rad);
this.rad += rad;
if (this.rad >= Math.PI * 2) {
const n = Math.floor(this.rad / Math.PI / 2);
this.rad -= n * Math.PI * 2;
}
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
setScale(x: number, y: number = x) {
mat3.scale(this.mat, this.mat, [x / this.scaleX, y / this.scaleY]);
this.scaleX = x;
this.scaleY = y;
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
setTranslate(x: number, y: number) {
2024-05-10 17:33:27 +08:00
mat3.translate(this.mat, this.mat, [this.x - x, this.y - y]);
2024-05-09 23:49:53 +08:00
this.x = x;
this.y = y;
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
*/
setRotate(rad: number) {
mat3.rotate(this.mat, this.mat, rad - this.rad);
this.rad = rad;
this.modified = true;
2024-05-09 23:49:53 +08:00
}
/**
*
2024-05-09 23:49:53 +08:00
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
*/
transform(
a: number,
b: number,
c: number,
d: number,
e: number,
f: number
) {
mat3.multiply(
this.mat,
this.mat,
mat3.fromValues(a, b, 0, c, d, 0, e, f, 1)
);
this.calAttributes();
}
/**
*
2024-05-09 23:49:53 +08:00
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
*/
setTransform(
a: number,
b: number,
c: number,
d: number,
e: number,
f: number
) {
mat3.set(this.mat, a, b, 0, c, d, 0, e, f, 1);
this.calAttributes();
}
/**
* translation scaling rotation
*/
calAttributes() {
const [x, y] = getTranslation(this.mat);
const [scaleX, scaleY] = getScaling(this.mat);
const rad = getRotation(this.mat);
this.x = x;
this.y = y;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.rad = rad;
if (x === 0 && y === 0 && scaleX === 1 && scaleY === 1 && rad === 0) {
this.modified = false;
} else {
this.modified = true;
}
2024-05-09 23:49:53 +08:00
}
2024-05-16 22:43:24 +08:00
/**
*
* @param transform
2024-05-16 22:43:24 +08:00
*/
multiply(transform: Transform): Transform {
if (this.modified) {
const res = new Transform();
const mat = mat3.clone(this.mat);
mat3.multiply(mat, mat, transform.mat);
res.mat = mat;
return res;
} else {
return transform.clone();
}
2024-05-16 22:43:24 +08:00
}
/**
*
2024-05-16 22:43:24 +08:00
*/
clone() {
const transform = new Transform();
transform.mat = mat3.clone(this.mat);
return transform;
2024-05-16 22:43:24 +08:00
}
2024-05-09 23:49:53 +08:00
/**
*
* @param transform
2024-05-09 23:49:53 +08:00
* @param x
* @param y
*/
static transformed(transform: Transform, x: number, y: number) {
return multiplyVec3(transform.mat, [x, y, 1]);
2024-05-09 23:49:53 +08:00
}
/**
*
* @param transform
2024-05-09 23:49:53 +08:00
* @param x
* @param y
*/
static untransformed(transform: Transform, x: number, y: number) {
2024-05-09 23:49:53 +08:00
const invert = mat3.create();
mat3.invert(invert, transform.mat);
2024-05-09 23:49:53 +08:00
return multiplyVec3(invert, [x, y, 1]);
}
/** 单位矩阵 */
static readonly identity = new Transform();
2024-05-09 23:49:53 +08:00
}
function multiplyVec3(mat: ReadonlyMat3, vec: ReadonlyVec3) {
return vec3.fromValues(
mat[0] * vec[0] + mat[3] * vec[1] + mat[6] * vec[2],
mat[1] * vec[0] + mat[4] * vec[1] + mat[7] * vec[2],
mat[2] * vec[0] + mat[5] * vec[1] + mat[8] * vec[2]
);
}
function getTranslation(mat: ReadonlyMat3): vec2 {
return [mat[6], mat[7]];
}
function getScaling(mat: ReadonlyMat3): vec2 {
return [Math.hypot(mat[0], mat[3]), Math.hypot(mat[1], mat[4])];
}
function getRotation(mat: ReadonlyMat3): number {
return Math.atan2(mat[3], mat[0]);
}