1 /** 2 Inochi2D Deformer Nodes 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; 14 import inochi2d.nodes; 15 import inochi2d.common; 16 import inochi2d.core; 17 import numem.core.traits; 18 import nulib; 19 import numem; 20 21 public import inochi2d.nodes.deformer.meshdeformer; 22 public import inochi2d.nodes.deformer.latticedeformer; 23 24 /** 25 A node which deforms the vertex data of nodes beneath 26 it. 27 28 Deformations happen in world space 29 */ 30 @TypeId("Deformer", IN_MAKE_TAG!(0, 2)) 31 @TypeIdAbstract 32 abstract 33 class Deformer : Node, IDeformable { 34 private: 35 @nogc: 36 weak_vector!IDeformable toDeform_; 37 38 void scanPartsRecurse(Node node) { 39 40 // Don't need to scan null nodes 41 if (node is null) 42 return; 43 44 // Do the main check 45 if (IDeformable deformable = cast(IDeformable)node) 46 toDeform_ ~= deformable; 47 48 // Deformers already deform their children, and we deform 49 // them first, so don't exaggerate it through their children 50 if (!cast(Deformer)node) { 51 foreach (child; node.children) { 52 this.scanPartsRecurse(child); 53 } 54 } 55 } 56 57 protected: 58 59 /** 60 Serializes this node to a DataNode. 61 62 Params: 63 object = The DataNode to serialize to. 64 */ 65 override 66 void onSerialize(ref DataNode object) { 67 super.onSerialize(object); 68 } 69 70 /** 71 Deserializes this node from a DataNode. 72 73 Params: 74 object = The DataNode to deserialize from. 75 state = The state of the deserializer. 76 */ 77 override 78 void onDeserialize(ref DataNode object, ref ModelState state) { 79 super.onDeserialize(object, state); 80 } 81 82 /** 83 Called when the node is to finalize its deserialization from disk. 84 85 Params: 86 state = The state of the deserializer. 87 */ 88 override 89 void onFinalize(ref ModelState state) @nogc { 90 super.onFinalize(state); 91 this.rescan(); 92 } 93 94 /** 95 Called when the deformer's internal data should be 96 rebuilt. 97 */ 98 void onRebuild() { 99 } 100 101 /** 102 Called when the node is moved from one parent 103 to another. 104 105 Params: 106 from = The node that used to be this node's parent. 107 to = The node it was moved to. 108 index = The index the node was moved to. 109 */ 110 override 111 void onMoved(Node from, Node to, ptrdiff_t index) { 112 this.rescan(); 113 } 114 115 public: 116 117 ~this() { 118 } 119 120 /** 121 Constructs a new MeshGroup node 122 */ 123 this(Node parent = null) { 124 super(parent); 125 } 126 127 /** 128 A list of the nodes to deform. 129 */ 130 @property IDeformable[] toDeform() => toDeform_[0 .. $]; 131 132 /** 133 The control points of the deformer. 134 */ 135 abstract @property vec2[] controlPoints() @nogc; 136 abstract @property void controlPoints(vec2[] value) @nogc; 137 138 /** 139 The base position of the deformable's points. 140 */ 141 abstract @property const(vec2)[] basePoints() @nogc; 142 143 /** 144 The base matrix of the object before any parameters have been applied. 145 */ 146 override @property Basis deformBaseMatrix() @nogc => baseMatrix; 147 148 /** 149 World matrix of the deformable object. 150 */ 151 override @property Basis deformMatrix() @nogc => matrix; 152 153 /** 154 The points which may be deformed by the deformer. 155 */ 156 override @property vec2[] deformPoints() @nogc => controlPoints(); 157 158 /** 159 Deforms the IDeformable. 160 161 Params: 162 deformed = The deformation delta. 163 absolute = Whether the deformation is absolute, 164 replacing the original deformation. 165 */ 166 override void deform(vec2[] deformed, bool absolute) { 167 import nulib.math : min; 168 169 size_t m = min(deformPoints.length, deformed.length); 170 if (absolute) 171 deformPoints[0 .. m] = deformed[0 .. m]; 172 else 173 deformPoints[0 .. m] += deformed[0 .. m]; 174 } 175 176 /** 177 Deforms a single vertex in the IDeformable 178 179 Params: 180 offset = The offset into the point list to deform. 181 deform = The deformation delta. 182 absolute = Whether the deformation is absolute, 183 replacing the original deformation. 184 */ 185 override void deform(size_t offset, vec2 deform, bool absolute = false) { 186 if (offset >= deformPoints.length) 187 return; 188 189 if (absolute) 190 deformPoints[offset] = deform; 191 else 192 deformPoints[offset] += deform; 193 } 194 195 /** 196 Resets the deformation for the IDeformable. 197 */ 198 abstract void resetDeform(); 199 200 /** 201 Rescans the children of the deformer. 202 */ 203 final void rescan() { 204 toDeform_.clear(); 205 foreach (child; children) { 206 this.scanPartsRecurse(child); 207 } 208 209 // We now know what we're deforming, rebuild. 210 this.onRebuild(); 211 } 212 } 213 214 mixin Register!(Deformer, in_node_registry); 215 216 /** 217 A deformer look-up-table for a deformer-to-mesh 218 mapping. 219 */ 220 struct DeformerLUT(alias mapfn) { 221 @nogc: 222 223 /** 224 LUT entries 225 */ 226 ptrdiff_t[2][] entries; 227 228 /** 229 Rebuilds the LUT. 230 */ 231 void rebuild(Parameters!(mapfn) params) { 232 nu_freea(entries); 233 entries = mapfn(params); 234 } 235 }