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;