Skip to content

Commit 93618ee

Browse files
hai.linhai.lin
hai.lin
authored and
hai.lin
committed
lunasvg pr
1 parent b1100f4 commit 93618ee

Some content is hidden

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

48 files changed

+36400
-262
lines changed

doc/develop/svg.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# SVG Optimization
2+
3+
Solve Godot built-in SVG parsing problem, some complex SVG files can not be displayed.
4+
5+
## Solution ideas
6+
7+
Use https://github.com/thorvg/thorvg libraries parse, Godot itself on the limited support SVG Tiny specification, won't cause complex SVG parsing.
8+
Use https://github.com/sammycage/lunasvg parsing library instead.
9+
10+
11+
### Modify the record
12+
13+
Replace the parsing file in the godot\modules\svg folder and import the lunasvg parsing library.
14+
Core code modification:
15+
16+
~~~
17+
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample) {
18+
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
19+
20+
auto document = lunasvg::Document::loadFromData((const char *)p_buffer, p_buffer_size);
21+
22+
uint32_t width = document->width(), height = document->height();
23+
24+
width *= p_scale;
25+
height *= p_scale;
26+
27+
auto bitmap = document->renderToBitmap(width, height, 0x00000000);
28+
29+
Vector<uint8_t> result;
30+
result.resize(width * height * 4);
31+
32+
uint32_t *buffer = (uint32_t *)bitmap.data();
33+
34+
for (uint32_t y = 0; y < height; y++) {
35+
for (uint32_t x = 0; x < width; x++) {
36+
uint32_t n = buffer[y * width + x];
37+
const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x;
38+
result.write[offset + 0] = (n >> 16) & 0xff;
39+
result.write[offset + 1] = (n >> 8) & 0xff;
40+
result.write[offset + 2] = n & 0xff;
41+
result.write[offset + 3] = (n >> 24) & 0xff;
42+
}
43+
}
44+
45+
p_image->set_data(width, height, false, Image::FORMAT_RGBA8, result);
46+
47+
return OK;
48+
}
49+
~~~
50+
51+
52+
TODO
53+
54+
Add large resolution svg cache

doc/develop/svg.zh.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# SVG优化
2+
3+
解决Godot自带SVG解析问题,部分复杂SVG文件无法显示。
4+
5+
## 解决思路
6+
7+
Godot自身使用 https://github.com/thorvg/thorvg 解析库解析,其支持SVG Tiny规范有限制,导致部分复杂SVG解析不了。
8+
使用https://github.com/sammycage/lunasvg解析库代替。
9+
10+
11+
### 修改记录
12+
13+
替换godot\modules\svg文件夹下解析文件,导入lunasvg解析库。
14+
核心代码修改:
15+
16+
~~~
17+
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample) {
18+
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
19+
20+
auto document = lunasvg::Document::loadFromData((const char *)p_buffer, p_buffer_size);
21+
22+
uint32_t width = document->width(), height = document->height();
23+
24+
width *= p_scale;
25+
height *= p_scale;
26+
27+
auto bitmap = document->renderToBitmap(width, height, 0x00000000);
28+
29+
Vector<uint8_t> result;
30+
result.resize(width * height * 4);
31+
32+
uint32_t *buffer = (uint32_t *)bitmap.data();
33+
34+
for (uint32_t y = 0; y < height; y++) {
35+
for (uint32_t x = 0; x < width; x++) {
36+
uint32_t n = buffer[y * width + x];
37+
const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x;
38+
result.write[offset + 0] = (n >> 16) & 0xff;
39+
result.write[offset + 1] = (n >> 8) & 0xff;
40+
result.write[offset + 2] = n & 0xff;
41+
result.write[offset + 3] = (n >> 24) & 0xff;
42+
}
43+
}
44+
45+
p_image->set_data(width, height, false, Image::FORMAT_RGBA8, result);
46+
47+
return OK;
48+
}
49+
~~~
50+
51+
52+
TODO
53+
54+
增加大分辨率图片cache

modules/svg/SCsub

+42
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,44 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"])
6464
# Enable ThorVG static object linking.
6565
env_svg.Append(CPPDEFINES=["TVG_STATIC"])
6666

67+
68+
69+
# ----------- Luna ----------------
70+
thirdparty_dir2 = "#thirdparty/lunasvg/"
71+
thirdparty_obj2 = []
72+
thirdparty_sources2 = [
73+
"source/graphics.cpp",
74+
"source/lunasvg.cpp",
75+
"source/plutovg-blend.c",
76+
"source/plutovg-canvas.c",
77+
"source/plutovg-font.c",
78+
"source/plutovg-ft-math.c",
79+
"source/plutovg-ft-raster.c",
80+
"source/plutovg-ft-stroker.c",
81+
"source/plutovg-matrix.c",
82+
"source/plutovg-paint.c",
83+
"source/plutovg-path.c",
84+
"source/plutovg-rasterize.c",
85+
"source/plutovg-surface.c",
86+
"source/svgelement.cpp",
87+
"source/svggeometryelement.cpp",
88+
"source/svglayoutstate.cpp",
89+
"source/svgpaintelement.cpp",
90+
"source/svgparser.cpp",
91+
"source/svgproperty.cpp",
92+
"source/svgrenderstate.cpp",
93+
"source/svgtextelement.cpp",
94+
]
95+
thirdparty_sources2 = [thirdparty_dir2 + file for file in thirdparty_sources2]
96+
97+
env_svg.Prepend(CPPPATH=[thirdparty_dir2 + "include"])
98+
99+
# Enable lunasvg static object linking.
100+
env_svg.Append(CPPDEFINES=["PLUTOVG_BUILD", "PLUTOVG_BUILD_STATIC", "LUNASVG_BUILD", "LUNASVG_BUILD_STATIC"])
101+
102+
103+
#-------------------------------
104+
67105
env_thirdparty = env_svg.Clone()
68106
env_thirdparty.disable_warnings()
69107
env_thirdparty.Prepend(
@@ -81,6 +119,9 @@ env_thirdparty.Prepend(
81119
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
82120
env.modules_sources += thirdparty_obj
83121

122+
env_thirdparty.add_source_files(thirdparty_obj2, thirdparty_sources2)
123+
env.modules_sources += thirdparty_obj2
124+
84125
# Godot source files
85126

86127
module_obj = []
@@ -90,3 +131,4 @@ env.modules_sources += module_obj
90131

91132
# Needed to force rebuilding the module files when the thirdparty library is updated.
92133
env.Depends(module_obj, thirdparty_obj)
134+
env.Depends(module_obj, thirdparty_obj2)

modules/svg/image_loader_svg.cpp

+16-56
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
#include "core/os/memory.h"
3434
#include "core/variant/variant.h"
3535

36-
#include <thorvg.h>
36+
#include <lunasvg.h>
37+
38+
#include <iostream>
3739

3840
HashMap<Color, Color> ImageLoaderSVG::forced_color_map = HashMap<Color, Color>();
3941

@@ -80,75 +82,33 @@ Ref<Image> ImageLoaderSVG::load_mem_svg(const uint8_t *p_svg, int p_size, float
8082
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample) {
8183
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
8284

83-
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
84-
85-
tvg::Result result = picture->load((const char *)p_buffer, p_buffer_size, "svg", true);
86-
if (result != tvg::Result::Success) {
87-
return ERR_INVALID_DATA;
88-
}
89-
float fw, fh;
90-
picture->size(&fw, &fh);
91-
92-
uint32_t width = MAX(1, round(fw * p_scale));
93-
uint32_t height = MAX(1, round(fh * p_scale));
94-
95-
const uint32_t max_dimension = 16384;
96-
if (width > max_dimension || height > max_dimension) {
97-
WARN_PRINT(vformat(
98-
String::utf8("ImageLoaderSVG: Target canvas dimensions %d×%d (with scale %.2f) exceed the max supported dimensions %d×%d. The target canvas will be scaled down."),
99-
width, height, p_scale, max_dimension, max_dimension));
100-
width = MIN(width, max_dimension);
101-
height = MIN(height, max_dimension);
102-
}
85+
auto document = lunasvg::Document::loadFromData((const char *)p_buffer, p_buffer_size);
10386

104-
picture->size(width, height);
87+
uint32_t width = document->width(), height = document->height();
10588

106-
std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen();
107-
// Note: memalloc here, be sure to memfree before any return.
108-
uint32_t *buffer = (uint32_t *)memalloc(sizeof(uint32_t) * width * height);
89+
width *= p_scale;
90+
height *= p_scale;
10991

110-
tvg::Result res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888S);
111-
if (res != tvg::Result::Success) {
112-
memfree(buffer);
113-
ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't set target on ThorVG canvas.");
114-
}
92+
auto bitmap = document->renderToBitmap(width, height, 0x00000000);
11593

116-
res = sw_canvas->push(std::move(picture));
117-
if (res != tvg::Result::Success) {
118-
memfree(buffer);
119-
ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't insert ThorVG picture on canvas.");
120-
}
121-
122-
res = sw_canvas->draw();
123-
if (res != tvg::Result::Success) {
124-
memfree(buffer);
125-
ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't draw ThorVG pictures on canvas.");
126-
}
127-
128-
res = sw_canvas->sync();
129-
if (res != tvg::Result::Success) {
130-
memfree(buffer);
131-
ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't sync ThorVG canvas.");
132-
}
94+
Vector<uint8_t> result;
95+
result.resize(width * height * 4);
13396

134-
Vector<uint8_t> image;
135-
image.resize(width * height * sizeof(uint32_t));
97+
uint32_t *buffer = (uint32_t *)bitmap.data();
13698

13799
for (uint32_t y = 0; y < height; y++) {
138100
for (uint32_t x = 0; x < width; x++) {
139101
uint32_t n = buffer[y * width + x];
140102
const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x;
141-
image.write[offset + 0] = (n >> 16) & 0xff;
142-
image.write[offset + 1] = (n >> 8) & 0xff;
143-
image.write[offset + 2] = n & 0xff;
144-
image.write[offset + 3] = (n >> 24) & 0xff;
103+
result.write[offset + 0] = (n >> 16) & 0xff;
104+
result.write[offset + 1] = (n >> 8) & 0xff;
105+
result.write[offset + 2] = n & 0xff;
106+
result.write[offset + 3] = (n >> 24) & 0xff;
145107
}
146108
}
147109

148-
res = sw_canvas->clear(true);
149-
memfree(buffer);
110+
p_image->set_data(width, height, false, Image::FORMAT_RGBA8, result);
150111

151-
p_image->set_data(width, height, false, Image::FORMAT_RGBA8, image);
152112
return OK;
153113
}
154114

modules/svg/register_types.cpp

-8
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,13 @@
3232

3333
#include "image_loader_svg.h"
3434

35-
#include <thorvg.h>
36-
3735
static Ref<ImageLoaderSVG> image_loader_svg;
3836

3937
void initialize_svg_module(ModuleInitializationLevel p_level) {
4038
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
4139
return;
4240
}
4341

44-
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
45-
if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) {
46-
return;
47-
}
48-
4942
image_loader_svg.instantiate();
5043
ImageLoader::add_image_format_loader(image_loader_svg);
5144
}
@@ -62,5 +55,4 @@ void uninitialize_svg_module(ModuleInitializationLevel p_level) {
6255

6356
ImageLoader::remove_image_format_loader(image_loader_svg);
6457
image_loader_svg.unref();
65-
tvg::Initializer::term(tvg::CanvasEngine::Sw);
6658
}

0 commit comments

Comments
 (0)