1 /*
2     Copyright © 2020, Inochi2D Project
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors:
6         Luna Nielsen
7         Asahi Lina
8 */
9 module inochi2d.math.transform;
10 public import inochi2d.math;
11 import inochi2d.fmt.serialize;
12 
13 /**
14     A transform
15 */
16 struct Transform {
17 private:
18     @Ignore
19     mat4 trs = mat4.identity;
20 
21 public:
22 
23     /**
24         The translation of the transform
25     */
26     vec3 translation = vec3(0, 0, 0);
27 
28     /**
29         The rotation of the transform
30     */
31     vec3 rotation = vec3(0, 0, 0);//; = quat.identity;
32 
33     /**
34         The scale of the transform
35     */
36     vec2 scale = vec2(1, 1);
37 
38     /**
39         Whether the transform should snap to pixels
40     */
41     bool pixelSnap = false;
42 
43     /**
44         Initialize a transform
45     */
46     this(vec3 translation, vec3 rotation = vec3(0), vec2 scale = vec2(1, 1)) {
47         this.translation = translation;
48         this.rotation = rotation;
49         this.scale = scale;
50     }
51 
52     Transform calcOffset(Transform other) {
53         Transform tnew;
54 
55         tnew.translation = this.translation+other.translation;
56         tnew.rotation = this.rotation+other.rotation;
57         tnew.scale = this.scale*other.scale;
58         tnew.update();
59 
60         return tnew;
61     }
62 
63     /**
64         Returns the result of 2 transforms multiplied together
65     */
66     Transform opBinary(string op : "*")(Transform other) {
67         Transform tnew;
68 
69         mat4 strs = other.trs * this.trs;
70         
71         // TRANSLATION
72         tnew.translation = vec3(strs * vec4(1, 1, 1, 1));
73         
74         // ROTATION
75         tnew.rotation = this.rotation+other.rotation;
76         
77         // SCALE
78         tnew.scale = this.scale*other.scale;
79         tnew.trs = strs;
80         tnew.update();
81         return tnew;
82     }
83 
84     /**
85         Gets the matrix for this transform
86     */
87     @Ignore
88     mat4 matrix() {
89         return trs;
90     }
91 
92     /**
93         Updates the internal matrix of this transform
94     */
95     void update() {
96         trs = 
97             mat4.translation(this.translation) *
98             quat.eulerRotation(this.rotation.x, this.rotation.y, this.rotation.z).toMatrix!(4, 4) *
99             mat4.scaling(this.scale.x, this.scale.y, 1);
100     }
101 
102     void clear() {
103         translation = vec3(0);
104         rotation = vec3(0);
105         scale = vec2(1, 1);
106     }
107 
108     @Ignore
109     string toString() {
110         import std.format : format;
111         return "%s,\n%s,\n%s\n%s".format(trs.toPrettyString, translation.toString, rotation.toString, scale.toString);
112     }
113 
114     void serialize(S)(ref S serializer) {
115         auto state = serializer.objectBegin();
116             serializer.putKey("trans");
117             translation.serialize(serializer);
118 
119             serializer.putKey("rot");
120             rotation.serialize(serializer);
121 
122             serializer.putKey("scale");
123             scale.serialize(serializer);
124 
125         serializer.objectEnd(state);
126     }
127 
128     SerdeException deserializeFromFghj(Fghj data) {
129         translation.deserialize(data["trans"]);
130         rotation.deserialize(data["rot"]);
131         scale.deserialize(data["scale"]);
132         return null;
133     }
134 }
135 /**
136     A 2D transform;
137 */
138 struct Transform2D {
139 private:
140     @Ignore
141     mat3 trs;
142 
143 public:
144     /**
145         Translate
146     */
147     vec2 translation;
148     /**
149         Scale
150     */
151     vec2 scale;
152     
153     /**
154         Rotation
155     */
156     float rotation;
157 
158     /**
159         Gets the matrix for this transform
160     */
161     mat3 matrix() {
162         return trs;
163     }
164 
165     /**
166         Updates the internal matrix of this transform
167     */
168     void update() {
169         mat3 translation_ = mat3.translation(vec3(translation, 0));
170         mat3 rotation_ = mat3.zRotation(rotation);
171         mat3 scale_ = mat3.scaling(scale.x, scale.y, 1);
172         trs =  translation_ * rotation_ * scale_;
173     }
174 
175 }