1 /** 2 1D Parameter 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.parameters.param1d; 16 import inochi2d.param.parameters; 17 import inochi2d.param.utils; 18 import inochi2d.core.registry; 19 import inochi2d.core.serde; 20 import inochi2d.core.math; 21 import inochi2d.core.guid; 22 import inochi2d.common; 23 import inochi2d.puppet; 24 import nulib; 25 import numem; 26 27 /** 28 1D variant of a parameter. 29 */ 30 @TypeId("1d", IN_MAKE_TAG!(1, 0)) 31 class Parameter1D : Parameter { 32 protected: 33 @nogc: 34 35 /** 36 Serialize this parameter. 37 */ 38 override 39 void onSerialize(ref DataNode object) { 40 super.onSerialize(object); 41 object["min"] = min.serialize(); 42 object["max"] = max.serialize(); 43 object["defaults"] = defaults.serialize(); 44 object["points"] = points.serialize(); 45 } 46 47 /** 48 Deserialize this parameter. 49 */ 50 override 51 void onDeserialize(ref DataNode object, ref ModelState state) { 52 super.onDeserialize(object, state); 53 object.tryGetRef(state, min, "min"); 54 object.tryGetRef(state, max, "max"); 55 object.tryGetRef(state, defaults, "defaults"); 56 57 // 0.8->0.9 upgrades 58 if (state.doUpgrade08) { 59 state.info("0.8->0.9: Upgrading 1D axis mapping..."); 60 object.tryGetRef(state, points, "axis_points"); 61 return; 62 } 63 64 object.tryGetRef(state, points, "points"); 65 } 66 67 /** 68 Finalizes the parameter. 69 70 Params: 71 puppet = The parent puppet 72 state = The state of the deserializer. 73 */ 74 override 75 void onFinalize(Puppet puppet, ref ModelState state) { 76 super.onFinalize(puppet, state); 77 value = defaults; 78 } 79 80 public: 81 82 /** 83 The current value of this parameter. 84 */ 85 float value = 0; 86 87 /** 88 The previous value of this parameter. 89 */ 90 float prev = 0; 91 92 /** 93 The default value of this parameter. 94 */ 95 float defaults = 0; 96 97 /** 98 The lower bound of this parameter. 99 */ 100 float min = 0; 101 102 /** 103 The upper bound of this parameter. 104 */ 105 float max = 1; 106 107 /** 108 Our keypoints' positions. 109 */ 110 vector!float points; 111 112 /** 113 The lower bound of this parameter. 114 */ 115 override @property float[] lowerBound() @trusted => (&min)[0 .. 1]; 116 117 /** 118 The upper bound of this parameter. 119 */ 120 override @property float[] upperBound() @trusted => (&max)[0 .. 1]; 121 122 /** 123 The current value of the parameter. 124 */ 125 override @property float[] currentValue() @trusted => (&value)[0 .. 1]; 126 127 /** 128 The dimensionality of the parameter. 129 */ 130 override @property int dimensions() => 1; 131 132 /** 133 Counts of elements in each axis. 134 */ 135 override @property uint[] elementCounts() { 136 static uint[1] counts; 137 counts = [cast(uint)points.length]; 138 return counts[0 .. 1]; 139 } 140 141 /** 142 Construct a new named parameter. 143 */ 144 this(string name = null) { 145 float[2] points_init = [0, 1]; 146 points = points_init; 147 guid = inNewGUID(); 148 this.name = name; 149 } 150 151 /** 152 Force this parameter to take on the given value. 153 154 Params: 155 value = The new value this parameter will take on. 156 */ 157 void pushValue(float value) { 158 this.value = value; 159 } 160 161 /** 162 Find the keypoint index of the given position, as well as its normal. 163 164 Params: 165 pos = A position along our keypoints. Must be within min & max. 166 norm = The given position, normalized within its keypoint. 167 168 Returns: 169 The index of the keypoint the given position falls on. 170 */ 171 ptrdiff_t findKeypointAndNormal(float pos, out float norm) { 172 return searchPoints(points, pos, norm); 173 } 174 175 /** 176 Normalize the given position between min & max. 177 */ 178 float normalize(float pos) const { 179 return (pos - min) / (max - min); 180 } 181 182 /** 183 Linearly interpolate from min to max by the given value. 184 */ 185 float lerp(float norm) const { 186 return .lerp(min, max, norm); 187 } 188 189 /** 190 Update our bindings with the value of this parameter. 191 */ 192 override 193 void update() { 194 if (!active) 195 return; 196 197 float norm; 198 ptrdiff_t index = findKeypointAndNormal(value, norm); 199 if (index >= 0) { 200 foreach (binding; bindings) { 201 binding.apply(vec2u(index, 0), vec2(norm, 0)); 202 } 203 } 204 } 205 } 206 207 mixin Register!(Parameter1D, in_param_registry);