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 }