1 module inochi2d.godot.resources.puppet;
2 import godot.resource_format_loader;
3 import godot.resource_loader;
4 import godot.resource;
5 import godot.variant;
6 import godot;
7 
8 import inochi2d.puppet;
9 import numem;
10 
11 /**
12     A resource for an Inochi2D Puppet
13 */
14 @class_name("Inochi2DPuppetResource")
15 class PuppetResource : Resource {
16 private:
17 @nogc:
18     PackedArray!ubyte data_;
19 
20 public:
21 
22     /**
23         Data of the puppet.
24     */
25     final @property PackedArray!ubyte data() => data_;
26 
27     /**
28         Size of the model file in bytes.
29     */
30     @gd_export_custom(PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY)
31     final @property uint fileSize() => cast(uint)data_.size;
32 
33     /// Constructor
34     this() { }
35 
36     /**
37         Loads an Inochi2D puppet from file.
38     */
39     @gd_hide bool loadFile(String path) {
40         import godot.file_access : FileAccess;
41         import core.stdc.stdio : printf;
42 
43         // Load data from file.
44         this.data_ = FileAccess.getFileAsBytes(path);
45         return data_.ptrw !is null;
46     }
47 
48     /**
49         Realizes an instance of the puppet from the resource.
50     */
51     @gd_hide Puppet realize() {
52         import nulib.io.stream : MemoryStream;
53 
54         // Load puppet into stream
55         auto mstream = nogc_new!MemoryStream(data_[]);
56         scope(exit) {
57             // Yoink the ownership so we don't free the array.
58             mstream.take();
59             nogc_delete(mstream);
60         }
61 
62         // Parse puppet
63         auto puppet = Puppet.fromStream(mstream);
64         if (!puppet.isOK) {
65             printError(puppet.error);
66             return null;
67         }
68 
69         // Success!
70         return puppet.get();
71     }
72 }
73 mixin GodotClass!PuppetResource;
74 
75 /**
76     Puppet resource loader.
77 */
78 @gd_editor
79 @class_name("Inochi2DPuppetResourceFormatLoader")
80 class PuppetResourceFormatLoader : ResourceFormatLoader {
81 private:
82 @nogc:
83     __gshared PuppetResourceFormatLoader __instance;
84 
85 public:
86 
87     /**
88         Gets the list of extensions for files this loader is able to read.
89 
90         Returns:
91             A list of file extensions that this loader supports.
92     */
93     override PackedArray!String getRecognizedExtensions_() {
94         PackedArray!String str;
95         str.resize(2);
96         str.ptrw[0] = String("inp");
97         str.ptrw[1] = String("inx");
98         return str;
99     }
100 
101     /**
102         Tells Godot whether this format loader handles the given type.
103 
104         Params:
105             type = The name of the resource type to query.
106         
107         Returns:
108             $(D true) if this loader handles the given type,
109             $(D false) otherwise.
110     */
111     override bool handlesType_(StringName type) {
112         return type == classNameOf!PuppetResource;
113     }
114 
115     /**
116         Gets the resource type to create for a given path string.
117 
118         Params:
119             path = The path to the file that is to be loaded.
120 
121         Returns:
122             The name of the resource that should be loaded,
123             or a nil string if that file extension is not handled.
124     */
125     override String getResourceType_(String path) {
126         if (path.endsWith(".inp") || path.endsWith(".inx"))
127             return String(classNameOf!PuppetResource);
128         return String.init;
129     }
130 
131     /**
132         Loads the given resource from the given path.
133 
134         Params:
135             path =          The path to the file to load.
136             originalpath =  The original path of the file.
137             usesubthreads = Whether to use sub-threads.
138             cachemode =     The caching mode.
139         
140         Returns:
141             A variant wrapping a referenced resource on success,
142             $(D Variant.init) otherwise.
143     */
144     override Variant load_(String path, String originalpath, bool usesubthreads, long cachemode) {
145         if (PuppetResource res = gd_new!PuppetResource) {
146             if (res.loadFile(path))
147                 return Variant(gde_ref(res));
148         }
149         return Variant.init;
150     }
151 
152     /**
153         Special callback that is called by nugodot after all types have been loaded.
154     */
155     static void __gde_postregistration() {
156         __instance = gd_new!PuppetResourceFormatLoader();
157         ResourceLoader.instance.addResourceFormatLoader(__instance, true);
158     }
159 
160     /**
161         Special callback that is called by nugodot before all types get unloaded.
162     */
163     static void __gde_preunregistration() {
164         ResourceLoader.instance.removeResourceFormatLoader(__instance);
165         __instance = null;
166     }
167     
168 }
169 mixin GodotClass!PuppetResourceFormatLoader;