1 /*
2     Inochi2D Shapes Node
3 
4     Copyright © 2020, Inochi2D Project
5     Distributed under the 2-Clause BSD License, see LICENSE file.
6     
7     Authors: Luna Nielsen
8 */
9 module inochi2d.core.nodes.shapes;
10 import inochi2d.core.nodes.part;
11 import inochi2d.core.nodes;
12 import inochi2d.core;
13 import inochi2d.math;
14 
15 /**
16     A Shape Node
17 */
18 struct ShapeNode {
19     /**
20         The breakpoint in which the Shape Node activates
21     */
22     vec2 breakpoint;
23 
24     /**
25         The shape data
26     */
27     vec2[] shapeData;
28 }
29 
30 /**
31     NOTE: This needs to be here to allow for deserialization of this type
32 */
33 mixin InNode!Shapes;
34 
35 /**
36     Contains various deformation shapes that can be applied to
37     children of this node
38 */
39 @TypeId("Shapes")
40 class Shapes : Node {
41 protected:
42 
43     override
44     string typeId() { return "Shapes"; }
45     
46 public:
47     /**
48         Constructs a new Shapes node
49     */
50     this(Node parent = null) {
51         super(parent);
52     }
53 
54     /**
55         A list of the shape offsets to apply per part
56     */
57     ShapeNode[][Drawable] shapes;
58 
59     /**
60         The cursor inside the Shapes node
61     */
62     vec2 selector;
63 
64     override
65     void update() {
66         foreach(Drawable part, nodes; shapes) {
67             
68             size_t nodeLen = nodes.length;
69             float[] weights = new float[nodeLen];
70             float accWeight = 0;
71 
72             enum MAX_DIST = 1.5;
73 
74             // Calculate weighted average for each breakpoint
75             for(size_t i = 0; i < nodes.length; i++) {
76                 weights[i] = MAX_DIST-(nodes[i].breakpoint.distance(selector)/MAX_DIST);
77                 accWeight += weights[i];
78             }
79 
80             // Acount for weights outside 1.0
81             if (accWeight > 1) {
82                 for(size_t i = 0; i < weights.length; i++) {
83                     weights[i] /= nodeLen;
84                 }
85             }
86 
87             // Make sure our vertices buffer is ready
88             vec2[] vertices = new vec2[part.vertices.length];
89             foreach(i; 0..vertices.length) {
90                 vertices[i] = vec2(0);
91             }
92 
93             // Apply our weighted offsets
94             foreach(node; nodes) {
95                 for (size_t i = 0; i < node.shapeData.length; i++) {
96                     vertices[i] += weights[i] * node.shapeData[i];
97                 }
98             }
99             
100         }
101     }
102 }