1 /**
2     Transforms
3 
4     Copyright: 
5         Copyright © 2020-2026, Inochi2D Project
6     
7     License:
8         $(LINK2 https://github.com/Inochi2D/inochi2d/blob/main/LICENSE, BSD 2-clause License)
9     
10     Authors:
11         Luna Nielsen
12 */
13 module inochi2d.core.math.transform;
14 import inochi2d.core.math;
15 import inochi2d.core;
16 import inochi2d.common;
17 import numath;
18 
19 /**
20     A transform
21 */
22 struct Transform {
23 public:
24 @nogc:
25 
26     /**
27         The translation of the transform
28     */
29     vec3 translation = vec3(0, 0, 0);
30 
31     /**
32         The rotation of the transform
33     */
34     vec3 rotation = vec3(0, 0, 0);
35 
36     /**
37         The scale of the transform
38     */
39     vec2 scale = vec2(1, 1);
40 
41     /**
42         Returns the result of 2 transforms multiplied together
43     */
44     Transform opBinary(string op : "+")(Transform other) @nogc {
45         Transform tnew;
46         tnew.translation = this.translation + other.translation;
47         tnew.rotation = this.rotation + other.rotation;
48         tnew.scale = this.scale * other.scale;
49         return tnew;
50     }
51 
52     /**
53         Calculates the basis matrix for this transform.
54     */
55     Basis matrix() {
56         return Basis(
57                 mat4.translation(this.translation) *
58                 mat4.zRotation(this.rotation.z) * mat4.yRotation(
59                     this.rotation.y) * mat4.xRotation(this.rotation.x) *
60                 mat4.scaling(this.scale.x, this.scale.y, 1)
61         );
62     }
63 
64     /**
65         Clears the vector
66     */
67     void clear() {
68         translation = vec3(0);
69         rotation = vec3(0);
70         scale = vec2(1, 1);
71     }
72 
73     /**
74         Serializes the transform.
75     */
76     void onSerialize(ref DataNode object) {
77         object["trans"] = translation.data.serialize();
78         object["rot"] = rotation.data.serialize();
79         object["scale"] = scale.data.serialize();
80     }
81 
82     /**
83         Deserializes a transform from JSON.
84     */
85     void onDeserialize(ref DataNode object, ref ModelState state) {
86         object.tryGetRef(state, translation.data, "trans", [0, 0, 0]);
87         object.tryGetRef(state, rotation.data, "rot", [0, 0, 0]);
88         object.tryGetRef(state, scale.data, "scale", [1, 1]);
89     }
90 }
91 
92 /**
93     A 4x4 basis matrix.
94 */
95 struct Basis {
96 public:
97 @nogc:
98 
99     /**
100         The underlying matrix of the basis
101     */
102     mat4 matrix = mat4.identity;
103     alias matrix this;
104 
105     /**
106         The translation of the basis.
107     */
108     @property vec3 translation() pure => vec3(matrix.matrix[0][3], matrix.matrix[1][3], matrix.matrix[2][3]);
109 
110     /**
111         The scale of the basis
112     */
113     @property vec2 scale() pure => vec2(
114             vec3(matrix.matrix[0][0], matrix.matrix[1][0], matrix.matrix[2][0]).length(),
115             vec3(matrix.matrix[0][1], matrix.matrix[1][1], matrix.matrix[2][1]).length()
116     );
117 }