1 module inochi2d.core.nodes.defstack;
2 import inochi2d.core;
3 import inochi2d.math;
4 import inochi2d;
5 import std.exception : enforce;
6 
7 /**
8     A deformation
9 */
10 struct Deformation {
11 
12     /**
13         Deformed values
14     */
15     vec2[] vertexOffsets;
16 
17     void update(vec2[] points) {
18         vertexOffsets = points.dup;
19     }
20 
21     this(this) pure @safe nothrow {
22         vertexOffsets = vertexOffsets.dup;
23     }
24 
25     Deformation opUnary(string op : "-")() @safe pure nothrow {
26         Deformation new_;
27 
28         new_.vertexOffsets.length = vertexOffsets.length;
29         foreach(i; 0..vertexOffsets.length) {
30             new_.vertexOffsets[i] = -vertexOffsets[i];
31         }
32 
33         return new_;
34     }
35 
36     Deformation opBinary(string op : "*", T)(T other) @safe pure nothrow {
37         static if (is(T == Deformation)) {
38             Deformation new_;
39 
40             new_.vertexOffsets.length = vertexOffsets.length;
41 
42             foreach(i; 0..vertexOffsets.length) {
43                 new_.vertexOffsets[i] = vertexOffsets[i] * other.vertexOffsets[i];
44             }
45 
46             return new_;
47         } else static if (is(T == vec2)) {
48             Deformation new_;
49 
50             new_.vertexOffsets.length = vertexOffsets.length;
51 
52             foreach(i; 0..vertexOffsets.length) {
53                 new_.vertexOffsets[i] = vec2(vertexOffsets[i].x * other.x, vertexOffsets[i].y * other.y);
54             }
55 
56             return new_;
57         } else {
58             Deformation new_;
59 
60             new_.vertexOffsets.length = vertexOffsets.length;
61 
62             foreach(i; 0..vertexOffsets.length) {
63                 new_.vertexOffsets[i] = vertexOffsets[i] * other;
64             }
65 
66             return new_;
67         }
68     }
69 
70     Deformation opBinaryRight(string op : "*", T)(T other) @safe pure nothrow {
71         static if (is(T == Deformation)) {
72             Deformation new_;
73 
74             new_.vertexOffsets.length = vertexOffsets.length;
75 
76             foreach(i; 0..vertexOffsets.length) {
77                 new_.vertexOffsets[i] = other.vertexOffsets[i] * vertexOffsets[i];
78             }
79 
80             return new_;
81         } else static if (is(T == vec2)) {
82             Deformation new_;
83 
84             new_.vertexOffsets.length = vertexOffsets.length;
85 
86             foreach(i; 0..vertexOffsets.length) {
87                 new_.vertexOffsets[i] = vec2(other.x * vertexOffsets[i].x, other.y * vertexOffsets[i].y);
88             }
89 
90             return new_;
91         } else {
92             Deformation new_;
93 
94             new_.vertexOffsets.length = vertexOffsets.length;
95 
96             foreach(i; 0..vertexOffsets.length) {
97                 new_.vertexOffsets[i] = other * vertexOffsets[i];
98             }
99 
100             return new_;
101         }
102     }
103 
104     Deformation opBinary(string op : "+", T)(T other) @safe pure nothrow {
105         static if (is(T == Deformation)) {
106             Deformation new_;
107 
108             new_.vertexOffsets.length = vertexOffsets.length;
109 
110             foreach(i; 0..vertexOffsets.length) {
111                 new_.vertexOffsets[i] = vertexOffsets[i] + other.vertexOffsets[i];
112             }
113 
114             return new_;
115         } else static if (is(T == vec2)) {
116             Deformation new_;
117 
118             new_.vertexOffsets.length = vertexOffsets.length;
119 
120             foreach(i; 0..vertexOffsets.length) {
121                 new_.vertexOffsets[i] = vec2(vertexOffsets[i].x + other.x, vertexOffsets[i].y + other.y);
122             }
123 
124             return new_;
125         } else {
126             Deformation new_;
127 
128             new_.vertexOffsets.length = vertexOffsets.length;
129 
130             foreach(i; 0..vertexOffsets.length) {
131                 new_.vertexOffsets[i] = vertexOffsets[i] + other;
132             }
133 
134             return new_;
135         }
136     }
137 
138     Deformation opBinary(string op : "-", T)(T other) @safe pure nothrow {
139         static if (is(T == Deformation)) {
140             Deformation new_;
141 
142             new_.vertexOffsets.length = vertexOffsets.length;
143 
144             foreach(i; 0..vertexOffsets.length) {
145                 new_.vertexOffsets[i] = vertexOffsets[i] - other.vertexOffsets[i];
146             }
147 
148             return new_;
149         } else static if (is(T == vec2)) {
150             Deformation new_;
151 
152             new_.vertexOffsets.length = vertexOffsets.length;
153 
154             foreach(i; 0..vertexOffsets.length) {
155                 new_.vertexOffsets[i] = vec2(vertexOffsets[i].x - other.x, vertexOffsets[i].y - other.y);
156             }
157 
158             return new_;
159         } else {
160             Deformation new_;
161 
162             new_.vertexOffsets.length = vertexOffsets.length;
163 
164             foreach(i; 0..vertexOffsets.length) {
165                 new_.vertexOffsets[i] = vertexOffsets[i] - other;
166             }
167 
168             return new_;
169         }
170     }
171 
172     void serialize(S)(ref S serializer) {
173         import inochi2d.math.serialization : serialize;
174         auto state = serializer.arrayBegin();
175             foreach(offset; vertexOffsets) {
176                 serializer.elemBegin;
177                 offset.serialize(serializer);
178             }
179         serializer.arrayEnd(state);
180     }
181 
182     SerdeException deserializeFromFghj(Fghj data) {
183         import inochi2d.math.serialization : deserialize;
184         foreach(elem; data.byElement()) {
185             vec2 offset;
186             offset.deserialize(elem);
187 
188             vertexOffsets ~= offset;
189         }
190 
191         return null;
192     }
193 }
194 
195 /**
196     A stack of local deformations to apply to the mesh
197 */
198 struct DeformationStack {
199 private:
200     Drawable parent;
201 
202 public:
203     this(Drawable parent) {
204         this.parent = parent;
205     }
206 
207     /**
208         Push deformation on to stack
209     */
210     void push(ref Deformation deformation) {
211         enforce(this.parent.deformation.length == deformation.vertexOffsets.length, "Mismatched lengths");
212         foreach(i; 0..this.parent.deformation.length) {
213             this.parent.deformation[i] += deformation.vertexOffsets[i];
214         }
215         this.parent.notifyDeformPushed(deformation);
216     }
217     
218     void preUpdate() {
219         foreach(i; 0..this.parent.deformation.length) {
220             this.parent.deformation[i] = vec2(0);
221         }
222     }
223 
224     void update() {
225         parent.refreshDeform();
226     }
227 }