Skip to content

Commit 2de4969

Browse files
committed
Add Lottie resource importer using ThorVG
Add lottie importer for `.lot` and `.lottie` to import lottie as CompressedTexture2D, and support dropping it as AnimatedSprite2D in 2d editor.
1 parent 54278a4 commit 2de4969

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+29154
-1
lines changed

editor/plugins/canvas_item_editor_plugin.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "core/config/project_settings.h"
3434
#include "core/input/input.h"
35+
#include "core/io/resource_importer.h"
3536
#include "core/os/keyboard.h"
3637
#include "editor/debugger/editor_debugger_node.h"
3738
#include "editor/editor_main_screen.h"
@@ -48,6 +49,7 @@
4849
#include "editor/scene_tree_dock.h"
4950
#include "editor/themes/editor_scale.h"
5051
#include "editor/themes/editor_theme_manager.h"
52+
#include "scene/2d/animated_sprite_2d.h"
5153
#include "scene/2d/audio_stream_player_2d.h"
5254
#include "scene/2d/polygon_2d.h"
5355
#include "scene/2d/skeleton_2d.h"
@@ -62,6 +64,7 @@
6264
#include "scene/gui/view_panner.h"
6365
#include "scene/main/canvas_layer.h"
6466
#include "scene/main/window.h"
67+
#include "scene/resources/atlas_texture.h"
6568
#include "scene/resources/packed_scene.h"
6669
#include "scene/resources/style_box_texture.h"
6770

@@ -5945,6 +5948,24 @@ void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_chil
59455948
Vector2(0, texture_size.height)
59465949
};
59475950
undo_redo->add_do_property(p_child, "polygon", list);
5951+
} else if (Object::cast_to<AnimatedSprite2D>(p_child)) {
5952+
// Currently this metadata is only set by ResourceImporterLottie.
5953+
Dictionary meta = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
5954+
Ref<SpriteFrames> frames;
5955+
frames.instantiate();
5956+
frames->set_animation_speed(SceneStringName(default_), meta.get("fps", 5));
5957+
Size2i sprite_size = meta["sprite_size"];
5958+
for (int i = 0; i < (int)meta["frame_count"]; i++) {
5959+
int x = i % (int)meta["columns"] * sprite_size.width;
5960+
int y = i / (int)meta["columns"] * sprite_size.height;
5961+
Ref<AtlasTexture> atlas_texture;
5962+
atlas_texture.instantiate();
5963+
atlas_texture->set_atlas(texture);
5964+
atlas_texture->set_region(Rect2(x, y, sprite_size.width, sprite_size.height));
5965+
frames->add_frame(SceneStringName(default_), atlas_texture);
5966+
}
5967+
undo_redo->add_do_property(p_child, SceneStringName(autoplay), SceneStringName(default_));
5968+
undo_redo->add_do_property(p_child, "sprite_frames", frames);
59485969
}
59495970

59505971
// Compute the global position
@@ -6350,6 +6371,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
63506371
texture_node_types.push_back("GPUParticles2D");
63516372
texture_node_types.push_back("Polygon2D");
63526373
texture_node_types.push_back("TouchScreenButton");
6374+
texture_node_types.push_back("AnimatedSprite2D");
63536375
// Control
63546376
texture_node_types.push_back("TextureRect");
63556377
texture_node_types.push_back("TextureButton");

modules/svg/SCsub

+25-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,21 @@ thirdparty_sources = [
5959
"src/renderer/sw_engine/tvgSwStroke.cpp",
6060
]
6161

62+
if env.editor_build:
63+
thirdparty_sources += [
64+
"src/renderer/tvgAnimation.cpp",
65+
# Lottie loader
66+
"src/loaders/lottie/tvgLottieAnimation.cpp",
67+
"src/loaders/lottie/tvgLottieBuilder.cpp",
68+
# "src/loaders/lottie/tvgLottieExpressions.cpp",
69+
"src/loaders/lottie/tvgLottieInterpolator.cpp",
70+
"src/loaders/lottie/tvgLottieLoader.cpp",
71+
"src/loaders/lottie/tvgLottieModel.cpp",
72+
"src/loaders/lottie/tvgLottieModifier.cpp",
73+
"src/loaders/lottie/tvgLottieParser.cpp",
74+
"src/loaders/lottie/tvgLottieParserHandler.cpp",
75+
]
76+
6277
if env["module_webp_enabled"]:
6378
thirdparty_sources += ["src/loaders/external_webp/tvgWebpLoader.cpp"]
6479
env_svg.Append(CPPDEFINES=["THORVG_WEBP_LOADER_SUPPORT"])
@@ -72,6 +87,9 @@ env_svg.Append(CPPDEFINES=["TVG_STATIC"])
7287
# Explicit support for embedded images in svg.
7388
env_svg.Append(CPPDEFINES=["THORVG_FILE_IO_SUPPORT"])
7489

90+
if env.editor_build:
91+
env_svg.Append(CPPDEFINES=["THORVG_LOTTIE_LOADER_SUPPORT", "LOTTIE_ENABLED"])
92+
7593
env_thirdparty = env_svg.Clone()
7694
env_thirdparty.disable_warnings()
7795
env_thirdparty.Prepend(
@@ -85,6 +103,9 @@ env_thirdparty.Prepend(
85103
thirdparty_dir + "src/loaders/jpg",
86104
]
87105
)
106+
107+
if env.editor_build:
108+
env_thirdparty.Prepend(CPPPATH=[thirdparty_dir + "src/loaders/lottie"])
88109
if env["builtin_libpng"]:
89110
env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"])
90111
if env["module_webp_enabled"]:
@@ -99,7 +120,10 @@ env.modules_sources += thirdparty_obj
99120

100121
module_obj = []
101122

102-
env_svg.add_source_files(module_obj, "*.cpp")
123+
env_svg.add_source_files(module_obj, ["register_types.cpp", "image_loader_svg.cpp"])
124+
if env.editor_build:
125+
env_svg.add_source_files(module_obj, "editor/*.cpp")
126+
103127
env.modules_sources += module_obj
104128

105129
# Needed to force rebuilding the module files when the thirdparty library is updated.

modules/svg/config.py

+10
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@ def can_build(env, platform):
44

55
def configure(env):
66
pass
7+
8+
9+
def get_doc_classes():
10+
return [
11+
"ResourceImporterLottie",
12+
]
13+
14+
15+
def get_doc_path():
16+
return "doc_classes"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="ResourceImporterLottie" inherits="ResourceImporterTexture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
3+
<brief_description>
4+
Import a Lottie animation as a sprite sheet.
5+
</brief_description>
6+
<description>
7+
This imports a Lottie animation to a [CompressedTexture2D] with support for Lottie JSON and limited support for dotLottie (Only reads the first animation within dotLottie and ignores other resources).
8+
[b]Note:[/b] This importer only recognizes files with [code].lot[/code] (Lottie JSON) or [code].lottie[/code] (dotLottie) extension. You have to rename Lottie JSON files extension to [code].lot[/code] to import them.
9+
</description>
10+
<tutorials>
11+
</tutorials>
12+
<members>
13+
<member name="compress/channel_pack" type="int" setter="" getter="" default="0">
14+
Controls how color channels should be used in the imported texture.
15+
[b]sRGB Friendly:[/b] Prevents the RG color format from being used, as it does not support sRGB color.
16+
[b]Optimized:[/b] Allows the RG color format to be used if the texture does not use the blue channel. This reduces memory usage if the texture's blue channel can be discarded (all pixels must have a blue value of [code]0[/code]).
17+
</member>
18+
<member name="compress/hdr_compression" type="int" setter="" getter="" default="1">
19+
Controls how VRAM compression should be performed for HDR images.
20+
[b]Disabled:[/b] Never use VRAM compression for HDR textures, regardless of whether they're opaque or transparent. Instead, the texture is converted to RGBE9995 (9-bits per channel + 5-bit exponent = 32 bits per pixel) to reduce memory usage compared to a half-float or single-precision float image format.
21+
[b]Opaque Only:[/b] Only uses VRAM compression for opaque HDR textures. This is due to a limitation of HDR formats, as there is no VRAM-compressed HDR format that supports transparency at the same time.
22+
[b]Always:[/b] Force VRAM compression even for HDR textures with an alpha channel. To perform this, the alpha channel is discarded on import.
23+
[b]Note:[/b] Only effective on Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) images.
24+
</member>
25+
<member name="compress/high_quality" type="bool" setter="" getter="" default="false">
26+
If [code]true[/code], uses BPTC compression on desktop platforms and ASTC compression on mobile platforms. When using BPTC, BC7 is used for SDR textures and BC6H is used for HDR textures.
27+
If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures.
28+
BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]).
29+
</member>
30+
<member name="compress/lossy_quality" type="float" setter="" getter="" default="0.7">
31+
The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk.
32+
</member>
33+
<member name="compress/mode" type="int" setter="" getter="" default="0">
34+
The compression mode to use. Each compression mode provides a different tradeoff:
35+
[b]Lossless[/b]: Original quality, high memory usage, high size on disk, fast import.
36+
[b]Lossy:[/b] Reduced quality, high memory usage, low size on disk, fast import.
37+
[b]VRAM Compressed:[/b] Reduced quality, low memory usage, low size on disk, slowest import. Only use for textures in 3D scenes, not for 2D elements.
38+
[b]VRAM Uncompressed:[/b] Original quality, high memory usage, highest size on disk, fastest import.
39+
[b]Basis Universal:[/b] Reduced quality, low memory usage, lowest size on disk, slow import. Only use for textures in 3D scenes, not for 2D elements.
40+
See [url=$DOCS_URL/tutorials/assets_pipeline/importing_images.html#compress-mode]Compress mode[/url] in the manual for more details.
41+
</member>
42+
<member name="compress/normal_map" type="int" setter="" getter="" default="0">
43+
When using a texture as normal map, only the red and green channels are required. Given regular texture compression algorithms produce artifacts that don't look that nice in normal maps, the RGTC compression format is the best fit for this data. Forcing this option to Enable will make Godot import the image as RGTC compressed. By default, it's set to Detect. This means that if the texture is ever detected to be used as a normal map, it will be changed to Enable and reimported automatically.
44+
Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map's blue channel to take this into account. Built-in material shaders already ignore the blue channel in a normal map (regardless of the actual normal map's contents).
45+
</member>
46+
<member name="detect_3d/compress_to" type="int" setter="" getter="" default="1">
47+
This changes the [member compress/mode] option that is used when a texture is detected as being used in 3D.
48+
Changing this import option only has an effect if a texture is detected as being used in 3D. Changing this to [b]Disabled[/b] then reimporting will not change the existing compress mode on a texture (if it's detected to be used in 3D), but choosing [b]VRAM Compressed[/b] or [b]Basis Universal[/b] will.
49+
</member>
50+
<member name="editor/convert_colors_with_editor_theme" type="bool" setter="" getter="" default="false">
51+
If [code]true[/code], converts the imported image's colors to match [member EditorSettings.interface/theme/icon_and_font_color]. This assumes the image uses the exact same colors as [url=$DOCS_URL/contributing/development/editor/creating_icons.html]Godot's own color palette for editor icons[/url], with the source file designed for a dark editor theme. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise.
52+
[b]Note:[/b] Only available for SVG images.
53+
</member>
54+
<member name="editor/scale_with_editor_scale" type="bool" setter="" getter="" default="false">
55+
If [code]true[/code], scales the imported image to match [member EditorSettings.interface/editor/custom_display_scale]. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise.
56+
[b]Note:[/b] Only available for SVG images.
57+
</member>
58+
<member name="lottie/begin" type="float" setter="" getter="" default="0">
59+
The start of the Lottie animation in the range [code]0.0[/code] to [code]1.0[/code].
60+
</member>
61+
<member name="lottie/columns" type="int" setter="" getter="" default="0">
62+
The number of columns of the sprite sheet.
63+
</member>
64+
<member name="lottie/end" type="float" setter="" getter="" default="1">
65+
The end of the Lottie animation in the range [code]0.0[/code] to [code]1.0[/code]. Less than [member lottie/begin] will be considered as [member lottie/begin].
66+
</member>
67+
<member name="lottie/fps" type="float" setter="" getter="" default="30">
68+
The frame rate the Lottie should be rendered at. Higher values result in a larger image.
69+
</member>
70+
<member name="lottie/scale" type="float" setter="" getter="" default="1">
71+
The scale the Lottie should be rendered at, with [code]1.0[/code] being the original design size. Higher values result in a larger image.
72+
</member>
73+
<member name="lottie/size_limit" type="int" setter="" getter="" default="2048">
74+
If set to a value greater than [code]0[/code], the size of the imported Lottie texture is limited on import to a value smaller than or equal to the value specified here.
75+
[b]Note:[/b] Importing large Lottie textures in editor is slow, this option ensures import speed and ignores [member lottie/scale].
76+
</member>
77+
<member name="mipmaps/generate" type="bool" setter="" getter="" default="false">
78+
If [code]true[/code], smaller versions of the texture are generated on import. For example, a 64×64 texture will generate 6 mipmaps (32×32, 16×16, 8×8, 4×4, 2×2, 1×1). This has several benefits:
79+
- Textures will not become grainy in the distance (in 3D), or if scaled down due to [Camera2D] zoom or [CanvasItem] scale (in 2D).
80+
- Performance will improve if the texture is displayed in the distance, since sampling smaller versions of the original texture is faster and requires less memory bandwidth.
81+
The downside of mipmaps is that they increase memory usage by roughly 33%.
82+
It's recommended to enable mipmaps in 3D. However, in 2D, this should only be enabled if your project visibly benefits from having mipmaps enabled. If the camera never zooms out significantly, there won't be a benefit to enabling mipmaps but memory usage will increase.
83+
</member>
84+
<member name="mipmaps/limit" type="int" setter="" getter="" default="-1">
85+
Unimplemented. This currently has no effect when changed.
86+
</member>
87+
<member name="process/fix_alpha_border" type="bool" setter="" getter="" default="true">
88+
If [code]true[/code], puts pixels of the same surrounding color in transition from transparent to opaque areas. For textures displayed with bilinear filtering, this helps to reduce the outline effect when exporting images from an image editor.
89+
It's recommended to leave this enabled (as it is by default), unless this causes issues for a particular image.
90+
</member>
91+
<member name="process/hdr_as_srgb" type="bool" setter="" getter="" default="false">
92+
Some HDR images you can find online may be broken and contain sRGB color data (instead of linear color data). It is advised not to use those files. If you absolutely have to, enabling [member process/hdr_as_srgb] will make them look correct.
93+
[b]Warning:[/b] Enabling [member process/hdr_as_srgb] on well-formatted HDR images will cause the resulting image to look too dark, so leave this on [code]false[/code] if unsure.
94+
</member>
95+
<member name="process/hdr_clamp_exposure" type="bool" setter="" getter="" default="false">
96+
If [code]true[/code], clamps exposure in the imported high dynamic range images using a smart clamping formula (without introducing [i]visible[/i] clipping).
97+
Some HDR panorama images you can find online may contain extremely bright pixels, due to being taken from real life sources without any clipping.
98+
While these HDR panorama images are accurate to real life, this can cause the radiance map generated by Godot to contain sparkles when used as a background sky. This can be seen in material reflections (even on rough materials in extreme cases). Enabling [member process/hdr_clamp_exposure] can resolve this.
99+
</member>
100+
<member name="process/normal_map_invert_y" type="bool" setter="" getter="" default="false">
101+
If [code]true[/code], convert the normal map from Y- (DirectX-style) to Y+ (OpenGL-style) by inverting its green color channel. This is the normal map convention expected by Godot.
102+
More information about normal maps (including a coordinate order table for popular engines) can be found [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details]here[/url].
103+
</member>
104+
<member name="process/premult_alpha" type="bool" setter="" getter="" default="false">
105+
An alternative to fixing darkened borders with [member process/fix_alpha_border] is to use premultiplied alpha. By enabling this option, the texture will be converted to this format. A premultiplied alpha texture requires specific materials to be displayed correctly:
106+
- In 2D, a [CanvasItemMaterial] will need to be created and configured to use the [constant CanvasItemMaterial.BLEND_MODE_PREMULT_ALPHA] blend mode on [CanvasItem]s that use this texture. In custom [code]@canvas_item[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used.
107+
- In 3D, a [BaseMaterial3D] will need to be created and configured to use the [constant BaseMaterial3D.BLEND_MODE_PREMULT_ALPHA] blend mode on materials that use this texture. In custom [code]spatial[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used.
108+
</member>
109+
<member name="process/size_limit" type="int" setter="" getter="" default="0">
110+
If set to a value greater than [code]0[/code], the size of the texture is limited on import to a value smaller than or equal to the value specified here. For non-square textures, the size limit affects the longer dimension, with the shorter dimension scaled to preserve aspect ratio. Resizing is performed using cubic interpolation.
111+
This can be used to reduce memory usage without affecting the source images, or avoid issues with textures not displaying on mobile/web platforms (as these usually can't display textures larger than 4096×4096).
112+
[b]Note:[/b] Even if this is set to [code]0[/code], import size is limited to the following dimensions for technical reasons. Depending on [member compress/mode], textures will be downsampled on import if necessary:
113+
- [b]Lossy:[/b] 16383 pixels width or height, whichever is larger;
114+
- [b]Basis Universal:[/b] 16384 pixels width or height, whichever is larger;
115+
- [b]All other modes:[/b] 32768 pixels width or height, whichever is larger.
116+
</member>
117+
<member name="roughness/mode" type="int" setter="" getter="" default="0">
118+
The color channel to consider as a roughness map in this texture. Only effective if [member roughness/src_normal] is not empty.
119+
</member>
120+
<member name="roughness/src_normal" type="String" setter="" getter="" default="&quot;&quot;">
121+
The path to the texture to consider as a normal map for roughness filtering on import. Specifying this can help decrease specular aliasing slightly in 3D.
122+
Roughness filtering on import is only used in 3D rendering, not 2D.
123+
</member>
124+
<member name="svg/scale" type="float" setter="" getter="" default="1.0">
125+
The scale the SVG should be rendered at, with [code]1.0[/code] being the original design size. Higher values result in a larger image. Note that unlike font oversampling, this affects the size the SVG is rendered at in 2D. See also [member editor/scale_with_editor_scale].
126+
[b]Note:[/b] Only available for SVG images.
127+
</member>
128+
</members>
129+
</class>

0 commit comments

Comments
 (0)