1 module inochi2d.core.puppet;
2 import inochi2d.fmt.serialize;
3 import inochi2d.core;
4 import inochi2d.math;
5 import std.algorithm.sorting;
6 import std.exception;
7 import std.format;
8 import std.file;
9 import std.path : extension;
10 import std.json;
11 
12 /**
13     Magic value meaning that the model has no thumbnail
14 */
15 enum NO_THUMBNAIL = uint.max;
16 
17 enum PuppetAllowedUsers {
18     /**
19         Only the author(s) are allowed to use the puppet
20     */
21     OnlyAuthor = "onlyAuthor",
22 
23     /**
24         Only licensee(s) are allowed to use the puppet
25     */
26     OnlyLicensee = "onlyLicensee",
27 
28     /**
29         Everyone may use the model
30     */
31     Everyone = "everyone"
32 }
33 
34 enum PuppetAllowedRedistribution {
35     /**
36         Redistribution is prohibited
37     */
38     Prohibited = "prohibited",
39 
40     /**
41         Redistribution is allowed, but only under
42         the same license as the original.
43     */
44     ViralLicense = "viralLicense",
45 
46     /**
47         Redistribution is allowed, and the puppet
48         may be redistributed under a different
49         license than the original.
50 
51         This goes in conjunction with modification rights.
52     */
53     CopyleftLicense = "copyleftLicense"
54 }
55 
56 enum PuppetAllowedModification {
57     /**
58         Modification is prohibited
59     */
60     Prohibited = "prohibited",
61 
62     /**
63         Modification is only allowed for personal use
64     */
65     AllowPersonal = "allowPersonal",
66 
67     /**
68         Modification is allowed with redistribution,
69         see allowedRedistribution for redistribution terms.
70     */
71     AllowRedistribute = "allowRedistribute",
72 }
73 
74 class PuppetUsageRights {
75     /**
76         Who is allowed to use the puppet?
77     */
78     @Optional
79     PuppetAllowedUsers allowedUsers = PuppetAllowedUsers.OnlyAuthor;
80 
81     /**
82         Whether violence content is allowed
83     */
84     @Optional
85     bool allowViolence = false;
86 
87     /**
88         Whether sexual content is allowed
89     */
90     @Optional
91     bool allowSexual = false;
92 
93     /**
94         Whether commerical use is allowed
95     */
96     @Optional
97     bool allowCommercial = false;
98 
99     /**
100         Whether a model may be redistributed
101     */
102     @Optional
103     PuppetAllowedRedistribution allowRedistribution = PuppetAllowedRedistribution.Prohibited;
104 
105     /**
106         Whether a model may be modified
107     */
108     @Optional
109     PuppetAllowedModification allowModification = PuppetAllowedModification.Prohibited;
110 
111     /**
112         Whether the author(s) must be attributed for use.
113     */
114     @Optional
115     bool requireAttribution = false;
116 }
117 
118 /**
119     Puppet meta information
120 */
121 class PuppetMeta {
122 
123     /**
124         Name of the puppet
125     */
126     string name;
127     /**
128         Version of the Inochi2D spec that was used for creating this model
129     */
130     @Name("version")
131     string version_ = "1.0-alpha";
132 
133     /**
134         Rigger(s) of the puppet
135     */
136     @Optional
137     string rigger;
138 
139     /**
140         Artist(s) of the puppet
141     */
142     @Optional
143     string artist;
144 
145     /**
146         Usage Rights of the puppet
147     */
148     @Optional
149     PuppetUsageRights rights;
150 
151     /**
152         Copyright string
153     */
154     @Optional
155     string copyright;
156 
157     /**
158         URL of license
159     */
160     @Optional
161     string licenseURL;
162 
163     /**
164         Contact information of the first author
165     */
166     @Optional
167     string contact;
168 
169     /**
170         Link to the origin of this puppet
171     */
172     @Optional
173     string reference;
174 
175     /**
176         Texture ID of this puppet's thumbnail
177     */
178     @Optional
179     uint thumbnailId = NO_THUMBNAIL;
180 
181     /**
182         Whether the puppet should preserve pixel borders.
183         This feature is mainly useful for puppets which use pixel art.
184     */
185     @Optional
186     bool preservePixels = false;
187 }
188 
189 /**
190     Puppet physics settings
191 */
192 class PuppetPhysics {
193     @Optional
194     float pixelsPerMeter = 1000;
195 
196     @Optional
197     float gravity = 9.8;
198 }
199 
200 /**
201     A puppet
202 */
203 class Puppet {
204 private:
205     /**
206         An internal puppet root node
207     */
208     @Ignore
209     Node puppetRootNode;
210 
211     /**
212         A list of parts that are not masked by other parts
213 
214         for Z sorting
215     */
216     @Ignore
217     Node[] rootParts;
218 
219     /**
220         A list of drivers that need to run to update the puppet
221     */
222     Driver[] drivers;
223 
224     /**
225         A list of parameters that are driven by drivers
226     */
227     Driver[Parameter] drivenParameters;
228 
229     void scanPartsRecurse(ref Node node, bool driversOnly = false) {
230 
231         // Don't need to scan null nodes
232         if (node is null) return;
233 
234         // Collect Drivers
235         if (Driver part = cast(Driver)node) {
236             drivers ~= part;
237             foreach(Parameter param; part.getAffectedParameters())
238                 drivenParameters[param] = part;
239         } else if (!driversOnly) {
240             // Collect drawable nodes only if we aren't inside a Composite node
241 
242             if (Composite composite = cast(Composite)node) {
243                 // Composite nodes handle and keep their own root node list, as such we should just draw them directly
244                 composite.scanParts();
245                 rootParts ~= composite;
246 
247                 // For this subtree, only look for Drivers
248                 driversOnly = true;
249             } else if (Part part = cast(Part)node) {
250                 // Collect Part nodes
251                 rootParts ~= part;
252             }
253             // Non-part nodes just need to be recursed through,
254             // they don't draw anything.
255         }
256 
257         // Recurse through children nodes
258         foreach(child; node.children) {
259             scanPartsRecurse(child, driversOnly);
260         }
261     }
262 
263     final void scanParts(bool reparent = false)(ref Node node) {
264 
265         // We want rootParts to be cleared so that we
266         // don't draw the same part multiple times
267         // and if the node tree changed we want to reflect those changes
268         // not the old node tree.
269         rootParts = [];
270 
271         // Same for drivers
272         drivers = [];
273         drivenParameters.clear();
274 
275         this.scanPartsRecurse(node);
276 
277         // To make sure the GC can collect any nodes that aren't referenced
278         // anymore, we clear its children first, then assign its new child
279         // to our "new" root node. In some cases the root node will be
280         // quite different.
281         static if (reparent) { 
282             if (puppetRootNode !is null) puppetRootNode.clearChildren();
283             node.parent = puppetRootNode;
284         }
285     }
286 
287     void selfSort() {
288         import std.math : cmp;
289         sort!((a, b) => cmp(
290             a.zSort, 
291             b.zSort) > 0)(rootParts);
292     }
293 
294     Node findNode(Node n, string name) {
295 
296         // Name matches!
297         if (n.name == name) return n;
298 
299         // Recurse through children
300         foreach(child; n.children) {
301             if (Node c = findNode(child, name)) return c;
302         }
303 
304         // Not found
305         return null;
306     }
307 
308     Node findNode(Node n, uint uuid) {
309 
310         // Name matches!
311         if (n.uuid == uuid) return n;
312 
313         // Recurse through children
314         foreach(child; n.children) {
315             if (Node c = findNode(child, uuid)) return c;
316         }
317 
318         // Not found
319         return null;
320     }
321 
322 public:
323     /**
324         Meta information about this puppet
325     */
326     @Name("meta")
327     PuppetMeta meta;
328 
329     /**
330         Global physics settings for this puppet
331     */
332     @Name("physics")
333     PuppetPhysics physics;
334 
335     /**
336         The root node of the puppet
337     */
338     @Name("nodes", "Root Node")
339     Node root;
340 
341     /**
342         Parameters
343     */
344     @Name("param", "Parameters")
345     @Optional
346     Parameter[] parameters;
347 
348     /**
349         Parameters
350     */
351     @Name("automation", "Automation")
352     @Optional
353     Automation[] automation;
354 
355     /**
356         INP Texture slots for this puppet
357     */
358     @Ignore
359     Texture[] textureSlots;
360 
361     /**
362         Extended vendor data
363     */
364     @Ignore
365     JSONValue[string] extData;
366 
367     /**
368         Whether parameters should be rendered
369     */
370     @Ignore
371     bool renderParameters = true;
372 
373     /**
374         Whether drivers should run
375     */
376     @Ignore
377     bool enableDrivers = true;
378 
379     /**
380         Creates a new puppet from nothing ()
381     */
382     this() { 
383         this.puppetRootNode = new Node(this); 
384         this.meta = new PuppetMeta();
385         this.physics = new PuppetPhysics();
386         root = new Node(this.puppetRootNode); 
387         root.name = "Root";
388     }
389 
390     /**
391         Creates a new puppet from a node tree
392     */
393     this(Node root) {
394         this.meta = new PuppetMeta();
395         this.physics = new PuppetPhysics();
396         this.root = root;
397         this.puppetRootNode = new Node(this);
398         this.root.name = "Root";
399         this.scanParts!true(this.root);
400         this.selfSort();
401     }
402 
403     /**
404         Updates the nodes
405     */
406     final void update() {
407 
408         // Rest additive offsets
409         foreach(parameter; parameters) {
410             parameter.preUpdate();
411         }
412 
413         // Update Automators
414         foreach(auto_; this.automation) {
415             auto_.update();
416         }
417 
418         root.beginUpdate();
419 
420         if (renderParameters) {
421 
422             // Update parameters
423             foreach(parameter; parameters) {
424                 if (!enableDrivers || parameter !in drivenParameters)
425                     parameter.update();
426             }
427         }
428 
429         // Ensure the transform tree is updated
430         root.transformChanged();
431 
432         if (renderParameters && enableDrivers) {
433             // Update parameter/node driver nodes (e.g. physics)
434             foreach(driver; drivers) {
435                 driver.updateDriver();
436             }
437         }
438 
439         // Update nodes
440         root.update();
441     }
442 
443     /**
444         Reset drivers/physics nodes
445     */
446     final void resetDrivers() {
447         foreach(driver; drivers) {
448             driver.reset();
449         }
450     }
451 
452     /**
453         Returns the index of a parameter by name
454     */
455     ptrdiff_t findParameterIndex(string name) {
456         foreach(i, parameter; parameters) {
457             if (parameter.name == name) {
458                 return i;
459             }
460         }
461         return -1;
462     }
463 
464     /**
465         Returns a parameter by UUID
466     */
467     Parameter findParameter(uint uuid) {
468         foreach(i, parameter; parameters) {
469             if (parameter.uuid == uuid) {
470                 return parameter;
471             }
472         }
473         return null;
474     }
475 
476     /**
477         Draws the puppet
478     */
479     final void draw() {
480         this.selfSort();
481 
482         foreach(rootPart; rootParts) {
483             if (!rootPart.renderEnabled) continue;
484             rootPart.drawOne();
485         }
486     }
487 
488     /**
489         Removes a parameter from this puppet
490     */
491     final void removeParameter(Parameter param) {
492         import std.algorithm.searching : countUntil;
493         import std.algorithm.mutation : remove;
494         ptrdiff_t idx = parameters.countUntil(param);
495         if (idx >= 0) {
496             parameters = parameters.remove(idx);
497         }
498     }
499 
500     /**
501         Gets this puppet's root transform
502     */
503     final Transform transform() {
504         return puppetRootNode.transform;
505     }
506 
507     /**
508         Rescans the puppet's nodes
509 
510         Run this every time you change the layout of the puppet's node tree
511     */
512     final void rescanNodes() {
513         this.scanParts!false(root);
514     }
515 
516     /**
517         Updates the texture state for all texture slots.
518     */
519     final void updateTextureState() {
520 
521         // Update filtering mode for texture slots
522         foreach(texutre; textureSlots) {
523             texutre.setFiltering(meta.preservePixels ? Filtering.Point : Filtering.Linear);
524         }
525     }
526 
527     /**
528         Finds Node by its name
529     */
530     T find(T = Node)(string name) if (is(T : Node)) {
531         return cast(T)findNode(root, name);
532     }
533 
534     /**
535         Finds Node by its unique id
536     */
537     T find(T = Node)(uint uuid) if (is(T : Node)) {
538         return cast(T)findNode(root, uuid);
539     }
540 
541     /**
542         Returns all the parts in the puppet
543     */
544     Part[] getAllParts() {
545         return findNodesType!Part(root);
546     }
547 
548     /**
549         Finds nodes based on their type
550     */
551     final T[] findNodesType(T)(Node n) if (is(T : Node)) {
552         T[] nodes;
553 
554         if (T item = cast(T)n) {
555             nodes ~= item;
556         }
557 
558         // Recurse through children
559         foreach(child; n.children) {
560             nodes ~= findNodesType!T(child);
561         }
562 
563         return nodes;
564     }
565 
566     /**
567         Adds a texture to a new slot if it doesn't already exist within this puppet
568     */
569     final uint addTextureToSlot(Texture texture) {
570         import std.algorithm.searching : canFind;
571 
572         // Add texture if we can't find it.
573         if (!textureSlots.canFind(texture)) textureSlots ~= texture;
574         return cast(uint)textureSlots.length-1;
575     }
576 
577     /**
578         Populate texture slots with all visible textures in the model
579     */
580     final void populateTextureSlots() {
581         if (textureSlots.length > 0) textureSlots.length = 0;
582         
583         foreach(part; getAllParts) {
584             foreach(texture; part.textures) {
585                 this.addTextureToSlot(texture);
586             }
587         }
588     }
589 
590     /**
591         Sets thumbnail of this puppet
592     */
593     final void setThumbnail(Texture texture) {
594         if (this.meta.thumbnailId == NO_THUMBNAIL) {
595             this.meta.thumbnailId = this.addTextureToSlot(texture);
596         } else {
597             textureSlots[this.meta.thumbnailId] = texture;
598         }
599     }
600 
601     /**
602         Gets the texture slot index for a texture
603 
604         returns -1 if none was found
605     */
606     final ptrdiff_t getTextureSlotIndexFor(Texture texture) {
607         import std.algorithm.searching : countUntil;
608         return textureSlots.countUntil(texture);
609     }
610 
611     /**
612         Clears this puppet's thumbnail
613 
614         By default it does not delete the texture assigned, pass in true to delete texture
615     */
616     final void clearThumbnail(bool deleteTexture = false) {
617         import std.algorithm.mutation : remove;
618         if (deleteTexture) textureSlots = remove(textureSlots, this.meta.thumbnailId);
619         this.meta.thumbnailId = NO_THUMBNAIL;
620     }
621 
622     /**
623         This cursed toString implementation outputs the puppet's
624         nodetree as a pretty printed tree.
625 
626         Please use a graphical viewer instead of this if you can,
627         eg. Inochi Creator.
628     */
629     override
630     string toString() {
631         import std.format : format;
632         import std.range : repeat, takeExactly;
633         import std.array : array;
634         bool[] lineSet;
635 
636         string toStringBranch(Node n, int indent, bool showLines = true) {
637 
638             lineSet ~= n.children.length > 0;
639             string getLineSet() {
640                 if (indent == 0) return "";
641                 string s = "";
642                 foreach(i; 1..lineSet.length) {
643                     s ~= lineSet[i-1] ? "│ " : "  ";
644                 }
645                 return s;
646             }
647 
648             string iden = getLineSet();
649 
650             string s = "%s[%s] %s <%s>\n".format(n.children.length > 0 ? "╭─" : "", n.typeId, n.name, n.uuid);
651             foreach(i, child; n.children) {
652                 string term = "├→";
653                 if (i == n.children.length-1) {
654                     term = "╰→";
655                     lineSet[indent] = false;
656                 }
657                 s ~= "%s%s%s".format(iden, term, toStringBranch(child, indent+1));
658             }
659 
660             lineSet.length--;
661 
662             return s;
663         }
664 
665         return toStringBranch(root, 0);
666     }
667 
668     /**
669         Serializes a puppet
670     */
671     void serialize(S)(ref S serializer) {
672         auto state = serializer.objectBegin;
673             serializer.putKey("meta");
674             serializer.serializeValue(meta);
675             serializer.putKey("physics");
676             serializer.serializeValue(physics);
677             serializer.putKey("nodes");
678             serializer.serializeValue(root);
679             serializer.putKey("param");
680             serializer.serializeValue(parameters);
681             serializer.putKey("automation");
682             serializer.serializeValue(automation);
683         serializer.objectEnd(state);
684     }
685 
686     /**
687         Deserializes a puppet
688     */
689     SerdeException deserializeFromFghj(Fghj data) {
690         if (auto exc = data["meta"].deserializeValue(this.meta)) return exc;
691         if (!data["physics"].isEmpty)
692             if (auto exc = data["physics"].deserializeValue(this.physics)) return exc;
693         if (auto exc = data["nodes"].deserializeValue(this.root)) return exc;
694         if (auto exc = data["param"].deserializeValue(this.parameters)) return exc;
695 
696         // Deserialize automation
697         foreach(key; data["automation"].byElement) {
698             string type;
699             if (auto exc = key["type"].deserializeValue(type)) return exc;
700 
701             if (inHasAutomationType(type)) {
702                 auto auto_ = inInstantiateAutomation(type, this);
703                 auto_.deserializeFromFghj(key);
704                 this.automation ~= auto_;
705             }
706         }
707         this.finalizeDeserialization(data);
708 
709         return null;
710     }
711 
712     /**
713         Finalizer
714     */
715     void finalizeDeserialization(Fghj data) {
716         this.root.setPuppet(this);
717         this.root.name = "Root";
718         this.puppetRootNode = new Node(this);
719         this.root.finalize();
720         foreach(parameter; parameters) {
721             parameter.finalize(this);
722         }
723         foreach(automation_; automation) {
724             automation_.finalize(this);
725         }
726         this.scanParts!true(this.root);
727         this.selfSort();
728     }
729 
730     /**
731         Gets the internal root parts array 
732 
733         Do note that some root parts may be Composites instead.
734     */
735     final Node[] getRootParts() {
736         return rootParts;
737     }
738 }