1 /**
2     Inochi2D Lattice Deformer Node
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.nodes.deformer.latticedeformer;
14 import inochi2d.nodes.deformer;
15 import inochi2d.nodes;
16 import inochi2d.common;
17 import inochi2d.core;
18 import numath;
19 import numem;
20 
21 /**
22     A deformer which uses a 2D lattice as the basis for
23     its deformation.
24 */
25 @TypeId("LatticeDeformer", IN_MAKE_TAG!(2, 2))
26 class LatticeDeformer : Deformer {
27 private:
28 @nogc:
29     int subdivs;
30     vec2 size_;
31 
32     float[][] weights_;
33     vec2[] latticeInitial;
34     vec2[] lattice;
35 
36     // Regenerates the lattice points.
37     void regenLattice() {
38         if (subdivs == 0)
39             return;
40 
41         this.latticeInitial = latticeInitial.nu_resize(subdivs * subdivs);
42         this.lattice = lattice.nu_resize(latticeInitial.length);
43         latticeInitial[0 .. $] = vec2.zero;
44 
45         vec2 iter = vec2(size_.x / subdivs, size_.y / subdivs);
46         foreach (i; 0 .. lattice.length) {
47             float x = mod(cast(float)i, cast(float)subdivs);
48             float y = cast(float)i / cast(float)subdivs;
49             latticeInitial[i] = iter * vec2(x, y);
50         }
51     }
52 
53     // Clears lattice weights
54     void clearWeights() {
55         foreach (i; 0 .. weights_.length) {
56             nu_freea(weights_[i]);
57         }
58         nu_freea(weights_);
59     }
60 
61 protected:
62 
63     /**
64         Serializes this node to a DataNode.
65 
66         Params:
67             object =    The DataNode to serialize to.
68     */
69     override
70     void onSerialize(ref DataNode object) {
71         super.onSerialize(object);
72         object["subdivisions"] = subdivs.serialize();
73     }
74 
75     /**
76         Deserializes this node from a DataNode.
77 
78         Params:
79             object =    The DataNode to deserialize from.
80             state =     The state of the deserializer.
81     */
82     override
83     void onDeserialize(ref DataNode object, ref ModelState state) {
84         super.onDeserialize(object, state);
85         object.tryGetRef(state, subdivs, "subdivisions");
86         object.tryGetRef(state, size_, "size");
87     }
88 
89     /**
90         Called when the node is to finalize its deserialization from disk.
91 
92         Params:
93             state =     The state of the deserializer.
94     */
95     override
96     void onFinalize(ref ModelState state) {
97         this.regenLattice();
98     }
99 
100     /**
101         Called during the update phase of a new frame.
102         
103         Params:
104             delta =     Time since the last frame.
105             drawList =  The drawlist for the active scene.
106     */
107     override
108     void onUpdate(float delta, DrawList drawList) {
109         super.onUpdate(delta, drawList);
110     }
111 
112 public:
113 
114     /**
115         The size of the lattice (in pixels)
116     */
117     @property vec2 size() => size_;
118     @property void size(vec2 value) {
119         this.size_ = value;
120         this.regenLattice();
121     }
122 
123     /**
124         The amount of subdivisions in the lattice.
125     */
126     @property int subdivisions() => subdivs;
127     @property void subdivisions(int value) {
128         this.subdivs = value;
129         this.regenLattice();
130     }
131 
132     /**
133         The base position of the deformable's points.
134     */
135     override @property const(vec2)[] basePoints() => latticeInitial;
136 
137     /**
138         The control points of the deformer.
139     */
140     override @property vec2[] controlPoints() => lattice;
141     override @property void controlPoints(vec2[] value) {
142         import nulib.math : min;
143 
144         size_t m = min(value.length, lattice.length);
145         lattice[0 .. m] = value[0 .. m];
146     }
147 
148     /**
149         Constructs a new MeshGroup node
150     */
151     this(Node parent = null) {
152         super(parent);
153     }
154 
155     /**
156         Deforms the IDeformable.
157 
158         Params:
159             deformed =  The deformation delta.
160             absolute =  Whether the deformation is absolute,
161                         replacing the original deformation.
162     */
163     override
164     void deform(vec2[] deformed, bool absolute) {
165         super.deform(deformed, absolute);
166     }
167 
168     /**
169         Resets the deformation.
170     */
171     override
172     void resetDeform() {
173         lattice[0 .. $] = latticeInitial[0 .. $];
174     }
175 }
176 
177 mixin Register!(LatticeDeformer, in_node_registry);