1 /**
2     Bridge parameter values to mesh deformations and more.
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         Mireille Arseneault
13         Hoshino Lina
14 */
15 module inochi2d.param.bindings;
16 import inochi2d.param.parameters;
17 import inochi2d.param.utils;
18 import inochi2d.core.registry;
19 import inochi2d.core.vector2d;
20 import inochi2d.core.serde;
21 import inochi2d.core.math;
22 import inochi2d.core.guid;
23 import inochi2d.common;
24 import inochi2d.puppet;
25 import inochi2d.nodes;
26 import nulib;
27 import numem;
28 
29 public import inochi2d.param.bindings.node;
30 public import inochi2d.param.bindings.deform;
31 public import inochi2d.param.bindings.property;
32 
33 /**
34     The public parameter binding registry.
35 */
36 __gshared TypeRegistry!(ParameterBinding, Parameter) in_binding_registry;
37 
38 /**
39     Deserialize a parameter binding depending on its shape.
40 
41     If the property name is "deform", assume it is a deformation binding.
42         Otherwise, assume it is a numeric value binding.
43 */
44 ParameterBinding tryDeserializeBinding(ref DataNode object, ref ModelState state, Parameter param) @nogc {
45     //if (state.doUpgrade08) {
46     //    if (auto prop = object.tryGet!string(state, "param_name", null)) {
47     //        state.info(nstring("0.8->0.9: upgrading binding ", prop, "..."));
48     //        auto binding = prop == "deform" ?
49     //            nogc_new!ParameterDeformBinding(param) :
50     //            nogc_new!ParameterPropertyBinding(param);
51 
52     //        binding.deserialize(object, state);
53     //        return cast(ParameterBinding)binding;
54     //    }
55 
56     //    state.warning(nstring("0.8->0.9: Encountered a unnamed binding, ignoring..."));
57     //    return null;
58     //}
59 
60     //if (auto binding = in_binding_registry.tryCreateFrom(object, param)) {
61     //    binding.deserialize(object, state);
62     //    return binding;
63     //}
64 
65     state.warning(nstring("Encountered untyped binding, ignoring..."));
66     return null;
67 }
68 
69 /**
70     Parameter binding base class.
71 */
72 abstract
73 class ParameterBinding : NuRefCounted, ISerializable, IDeserializable!ModelState {
74 protected:
75 @nogc:
76     Parameter parameter;
77     InterpolateMode interpMode = InterpolateMode.linear;
78 
79     /**
80         Serializes this binding.
81     */
82     override void onSerialize(ref DataNode object) {
83         object["interpolate_mode"] = cast(uint)interpMode;
84     }
85 
86     /**
87         Deserialize this binding.
88     */
89     override void onDeserialize(ref DataNode object, ref ModelState state) {
90         if (auto mode = "interpolate_mode" in object) {
91             if (mode.isNumber) {
92                 interpMode = cast(InterpolateMode)((*mode).tryGet!uint(state));
93             } else {
94                 interpMode = (*mode).tryGet!string(state).toInterpolateMode();
95             }
96         }
97     }
98 
99     /**
100         Finalizes the parameter binding.
101 
102         Params:
103             puppet =    The parent puppet
104             state =     The state of the deserializer.
105     */
106     void onFinalize(Puppet puppet, ref ModelState state) {
107     }
108 
109 public:
110 
111     /**
112         Construct a binding from its parameter.
113 
114         Params:
115             param = The parameter this binding will belong to.
116     */
117     this(Parameter param) {
118         this.parameter = param;
119     }
120 
121     /**
122         Apply the given interpolated keypoint to this binding.
123 
124         Params:
125             index = The index of the first keypoint in our quartet.
126             norm = The normalized position in our keypoint quartet.
127     */
128     abstract
129     void apply(vec2u index, vec2 norm);
130 
131     /**
132         Keypoint operation to insert a keypoint at the given position.
133     */
134     abstract
135     void insertKeypoint(ParameterAxis axis, uint index);
136 
137     /**
138         Keypoint operation to move a keypoint to the given position.
139     */
140     abstract
141     void moveKeypoint(ParameterAxis axis, uint index, uint dest);
142 
143     /**
144         Keypoint operation to delete the keypoint at the given position.
145     */
146     abstract
147     void deleteKeypoint(ParameterAxis axis, uint index);
148 
149     /**
150         Keypoint operation to scale a keypoint by a given factor.
151     */
152     abstract
153     void scaleKeypoint(ParameterAxis axis, uint index, float scale);
154 
155     /**
156         Keypoint operation to copy its value to another binding's keypoint.
157     */
158     abstract
159     void copyKeypoint(vec2u index, ParameterBinding other, vec2u dest);
160 
161     /**
162         Clear all keypoint values.
163     */
164     abstract
165     void clear();
166 
167     /**
168         Initialize the keypoint at the given index with its interpolated value.
169     */
170     abstract
171     void enable(vec2u index);
172 
173     /**
174         Reinitialize the keypoint at the given index to its default value.
175     */
176     abstract
177     void reset(vec2u index);
178 
179     /**
180         Clear the keypoint at the given index to its default value.
181     */
182     abstract
183     void disable(vec2u index);
184 
185     /**
186         Fill undefined keypoints with sensible defaults.
187     */
188     abstract
189     void fillBlanks();
190 
191     /**
192         Check whether the keypoint at the given index is defined.
193     */
194     abstract
195     bool isDefined(uint index) const;
196 
197     /**
198         Check whether this binding is compatible with the given node.
199     */
200     abstract
201     bool isCompatibleWith(Node other) const;
202 
203     /**
204         Serializes this parameter.
205 
206         Params:
207             object = The data node to deserialize.
208     */
209     final void serialize(ref DataNode object) {
210         this.onSerialize(object);
211     }
212 
213     /**
214         Deserializes this parameter.
215 
216         Params:
217             object =    The data node to deserialize.
218             state =     The state of the deserializer.
219     */
220     final void deserialize(ref DataNode object, ref ModelState state) {
221         this.onDeserialize(object, state);
222     }
223 
224     /**
225         Finalizes the parameter binding.
226 
227         Params:
228             puppet =    The parent puppet
229             state =     The state of the deserializer.
230     */
231     final void finalize(Puppet puppet, ref ModelState state) {
232         this.onFinalize(puppet, state);
233     }
234 }