Skip to content

Commit f54545a

Browse files
committed
Support controlling G4MF external data and URI-based buffer compression
1 parent fc1ede0 commit f54545a

File tree

8 files changed

+222
-65
lines changed

8 files changed

+222
-65
lines changed

addons/4d/doc_classes/G4MFState4D.xml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,26 @@
2929
Gets the index of the G4MF node in the state's [member g4mf_nodes] array corresponding to the given Godot node. This will return [code]-1[/code] if the node is not found. Since it is possible for a G4MF node to generate multiple Godot nodes, if this returns [code]-1[/code], you may wish to call this function again with the parent node to give it another try.
3030
</description>
3131
</method>
32+
<method name="is_text_file" qualifiers="const">
33+
<return type="bool" />
34+
<description>
35+
Returns [code]true[/code] if [member filename] indicates this is a text-based G4MF file, meaning that it has 4 or more characters (handles [code]".g4tf"[/code] and other non-recommended cases like [code]".g4tf.json"[/code]). Returns [code]false[/code] with extensions shorter than 4 characters, or for an empty filename (indicating this is a byte array in memory).
36+
</description>
37+
</method>
3238
<method name="reserve_unique_name">
3339
<return type="String" />
3440
<param index="0" name="requested" type="String" />
3541
<description>
3642
Reserves a unique name based on the requested name. This allows you to create a unique name for a node or resource in the G4MF file without conflicting with other names. If the requested name is already in use, a number will be appended to the name to make it unique. The number will be incremented until a unique name is found. The returned name is guaranteed to be unique relative to already reserved names.
3743
</description>
3844
</method>
45+
<method name="should_separate_resource_files" qualifiers="const">
46+
<return type="bool" />
47+
<description>
48+
Returns [code]true[/code] if resource files, such as images, should be separated into their own files. Returns [code]false[/code] if they should be embedded in the G4MF file. This is determined by the [member external_data_mode] property.
49+
Extensions should call this method to determine if they should save their resources in separate files. For example, an audio extension should use this to determine if it should save audio files in separate files such as [code].mp3[/code] files, or if it should embed them in the G4MF file in buffer views.
50+
</description>
51+
</method>
3952
</methods>
4053
<members>
4154
<member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default="&quot;&quot;">
@@ -44,6 +57,12 @@
4457
<member name="buffers" type="PackedByteArray[]" setter="set_buffers" getter="get_buffers" default="[]">
4558
The array of buffers in the G4MF file. This is used to store binary blobs of data, such as mesh data. Each buffer is used by a [G4MFBufferView4D] to access a slice of the buffer, which is then used by [G4MFAccessor4D] to access the data in the buffer in a typed way.
4659
</member>
60+
<member name="external_data_mode" type="int" setter="set_external_data_mode" getter="get_external_data_mode" enum="G4MFState4D.ExternalDataMode" default="0">
61+
When exporting a G4MF file, this determines where external data, such as images and binary buffers, should be stored.
62+
The default value is [constant EXTERNAL_DATA_MODE_AUTOMATIC], which automatically determines if data should be embedded or separated based on the file extension used, embedding for [code].glb[/code] files and separating for [code].gltf[/code] files. If you want different behavior, you can set this to one of the [enum ExternalDataMode] values.
63+
Saving resources like images to their own files can be useful for destinations where you need access to these files separately. For example, if the exported G4MF is added to the [code]res://[/code] folder of a Godot project, the default behavior of the Godot editor is to extract embedded images to their own files so they can be imported and compressed into GPU-optimized formats.
64+
Extensions should respect this setting by calling [method should_separate_resource_files] to determine if they should save their resources in separate files.
65+
</member>
4766
<member name="filename" type="String" setter="set_filename" getter="get_filename" default="&quot;&quot;">
4867
The filename of the G4MF file, including the file extension. If it ends with [code].g4tf[/code], this is a text-based G4MF, otherwise this is a binary G4MF. This will be set during import when appending from a file, and will be set during export when writing to a file. If writing to a buffer, this will be an empty string.
4968
</member>
@@ -72,4 +91,28 @@
7291
The array of Godot nodes corresponding to the G4MF nodes. This is used when importing a G4MF file and generating Godot nodes, after the nodes are generated, this array will have the same length as [member g4mf_nodes]. This is also used when converting a Godot scene to a G4MF file, after the nodes are converted, this array will have the same length as [member g4mf_nodes]. The node at each index corresponds to the G4MF node with the same index in the [member g4mf_nodes] array.
7392
</member>
7493
</members>
94+
<constants>
95+
<constant name="EXTERNAL_DATA_MODE_AUTOMATIC" value="0" enum="ExternalDataMode">
96+
When exporting a G4MF file, automatically determines if data should be embedded or separated based on the file extension used and if [member base_path] is valid. With this option, exporting a [code].g4tf[/code] file with a valid [member base_path] will behave like [constant EXTERNAL_DATA_MODE_SEPARATE_ALL_FILES]. If exporting a [code].g4b[/code] file, exporting to an in-memory buffer, or exporting with [member base_path] set to an empty string, this will behave like [constant EXTERNAL_DATA_MODE_EMBED_EVERYTHING].
97+
This option is suitable for most use cases. It behaves like Blender's "glTF Binary (.glb)" export option for [code].g4b[/code] files, and like Blender's "glTF Separate (.gltf + .bin + textures)" export option for [code].g4tf[/code] files.
98+
</constant>
99+
<constant name="EXTERNAL_DATA_MODE_EMBED_EVERYTHING" value="1" enum="ExternalDataMode">
100+
When exporting a G4MF file, embeds all data in the G4MF file, including images and binary buffers. For [code].g4b[/code] files, this will use the binary blob chunks at the end of the file to store the data in buffers.
101+
This option is useful when you want a single self-contained file. It behaves like Blender's "glTF Binary (.glb)" export option for [code].g4b[/code] files, and like Blender's "glTF Embedded (.gltf)" export option for [code].gltf[/code] files.
102+
</constant>
103+
<constant name="EXTERNAL_DATA_MODE_SEPARATE_ALL_FILES" value="2" enum="ExternalDataMode">
104+
When exporting a G4MF file, separates all files that can be saved in their own file formats into their own files, and also save all raw binary blobs, such as G4MF buffers, into separate [code].bin[/code] files.
105+
This option is useful when having the G4MF file's contents spread out over multiple files is desired, resulting in maximum human readability. It behaves like Blender's "glTF Separate (.gltf + .bin + textures)" export option.
106+
Extensions should respect this setting by calling [method should_separate_resource_files] to determine if they should save their resources in separate files.
107+
</constant>
108+
<constant name="EXTERNAL_DATA_MODE_SEPARATE_BINARY_BLOBS" value="3" enum="ExternalDataMode">
109+
When exporting a G4MF file, separates all raw binary blobs, such as G4MF buffers, into separate [code].bin[/code] files. Resources that can be saved in their own file formats, such as images, are embedded within G4MF buffers, and are stored in the [code].bin[/code] files.
110+
This option is useful if you need efficient storage of binary data while also keeping the number of files low. In the typical case, this option will result in only two files: the G4MF file and a single [code].bin[/code] file next to it.
111+
</constant>
112+
<constant name="EXTERNAL_DATA_MODE_SEPARATE_RESOURCE_FILES" value="4" enum="ExternalDataMode">
113+
When exporting a G4MF file, separates all resources that can be saved in their own file formats into their own files, such as images. This option does not separate buffers, meaning that binary blob data without a file type, such as mesh data, animation data, skin/skeleton data, and so on, are still embedded in the G4MF file.
114+
This option is useful if the exported G4MF file is intended to be added to the project folder in a game engine, so that the game engine can import the resources files separately, and optionally use them separately. Otherwise, game engines may extract embedded resources to their own files, resulting in duplicate data in the project folder.
115+
Extensions should respect this setting by calling [method should_separate_resource_files] to determine if they should save their resources in separate files.
116+
</constant>
117+
</constants>
75118
</class>

editor/import/g4mf/editor_export_dialog_g4mf_4d.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void EditorExportDialogG4MF4D::_export_scene_as_g4mf(const String &p_path) {
5252
ERR_FAIL_COND_SHOW_DIALOG(scene_root == nullptr, "G4MF error: Cannot export scene without a root node.");
5353
Ref<G4MFState4D> g4mf_state;
5454
g4mf_state.instantiate();
55+
g4mf_state->set_external_data_mode(_export_settings->get_external_data_mode());
5556
Error err = _g4mf_document->export_append_from_godot_scene(g4mf_state, scene_root);
5657
ERR_FAIL_COND_SHOW_DIALOG(err != OK, "G4MF editor export: Error while running export_append_from_godot_scene.");
5758
err = _g4mf_document->export_write_to_file(g4mf_state, p_path);

editor/import/g4mf/editor_export_settings_g4mf_4d.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ void EditorExportSettingsG4MF4D::_bind_methods() {
2121
ClassDB::bind_method(D_METHOD("set_compression_format", "compression_format"), &EditorExportSettingsG4MF4D::set_compression_format);
2222
ADD_PROPERTY(PropertyInfo(Variant::INT, "compression_format", PROPERTY_HINT_ENUM, "None,Zstd"), "set_compression_format", "get_compression_format");
2323

24+
ClassDB::bind_method(D_METHOD("get_external_data_mode"), &EditorExportSettingsG4MF4D::get_external_data_mode);
25+
ClassDB::bind_method(D_METHOD("set_external_data_mode", "external_data_mode"), &EditorExportSettingsG4MF4D::set_external_data_mode);
26+
ADD_PROPERTY(PropertyInfo(Variant::INT, "external_data_mode", PROPERTY_HINT_ENUM, "Automatic,Embed Everything,Separate All Files,Separate Binary Blobs,Separate Resource Files"), "set_external_data_mode", "get_external_data_mode");
27+
2428
ClassDB::bind_method(D_METHOD("setup", "g4mf_document"), &EditorExportSettingsG4MF4D::setup);
2529
}

editor/import/g4mf/editor_export_settings_g4mf_4d.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class EditorExportSettingsG4MF4D : public RefCounted {
66
GDCLASS(EditorExportSettingsG4MF4D, RefCounted);
77

88
Ref<G4MFDocument4D> _g4mf_document;
9+
G4MFState4D::ExternalDataMode _external_data_mode = G4MFState4D::ExternalDataMode::EXTERNAL_DATA_MODE_AUTOMATIC;
910

1011
protected:
1112
static void _bind_methods();
@@ -14,5 +15,8 @@ class EditorExportSettingsG4MF4D : public RefCounted {
1415
G4MFDocument4D::CompressionFormat get_compression_format() const;
1516
void set_compression_format(const G4MFDocument4D::CompressionFormat p_compression_format);
1617

18+
G4MFState4D::ExternalDataMode get_external_data_mode() const { return _external_data_mode; }
19+
void set_external_data_mode(const G4MFState4D::ExternalDataMode p_external_data_mode) { _external_data_mode = p_external_data_mode; }
20+
1721
void setup(Ref<G4MFDocument4D> p_g4mf_document);
1822
};

0 commit comments

Comments
 (0)