You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-16 14:00:40 +00:00
Improve font glyph cache packing shelf best height fit heuristic.
This commit is contained in:
@@ -262,7 +262,7 @@
|
|||||||
<param index="1" name="size" type="Vector2i" />
|
<param index="1" name="size" type="Vector2i" />
|
||||||
<param index="2" name="texture_index" type="int" />
|
<param index="2" name="texture_index" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns a copy of the array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
|
Returns a copy of the array containing glyph packing data.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_transform" qualifiers="const">
|
<method name="get_transform" qualifiers="const">
|
||||||
@@ -522,7 +522,7 @@
|
|||||||
<param index="2" name="texture_index" type="int" />
|
<param index="2" name="texture_index" type="int" />
|
||||||
<param index="3" name="offset" type="PackedInt32Array" />
|
<param index="3" name="offset" type="PackedInt32Array" />
|
||||||
<description>
|
<description>
|
||||||
Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty (for the fonts without dynamic glyph generation support).
|
Sets array containing glyph packing data.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="set_transform">
|
<method name="set_transform">
|
||||||
|
|||||||
@@ -413,7 +413,7 @@
|
|||||||
<param index="1" name="size" type="Vector2i" />
|
<param index="1" name="size" type="Vector2i" />
|
||||||
<param index="2" name="texture_index" type="int" />
|
<param index="2" name="texture_index" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
|
Returns array containing glyph packing data.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="font_get_transform" qualifiers="const">
|
<method name="font_get_transform" qualifiers="const">
|
||||||
@@ -824,7 +824,7 @@
|
|||||||
<param index="2" name="texture_index" type="int" />
|
<param index="2" name="texture_index" type="int" />
|
||||||
<param index="3" name="offset" type="PackedInt32Array" />
|
<param index="3" name="offset" type="PackedInt32Array" />
|
||||||
<description>
|
<description>
|
||||||
Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
|
Sets array containing glyph packing data.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="font_set_transform">
|
<method name="font_set_transform">
|
||||||
|
|||||||
@@ -788,58 +788,27 @@ String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {
|
|||||||
|
|
||||||
_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
|
_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
|
||||||
FontTexturePosition ret;
|
FontTexturePosition ret;
|
||||||
ret.index = -1;
|
|
||||||
|
|
||||||
int mw = p_width;
|
int mw = p_width;
|
||||||
int mh = p_height;
|
int mh = p_height;
|
||||||
|
|
||||||
for (int i = 0; i < p_data->textures.size(); i++) {
|
ShelfPackTexture *ct = p_data->textures.ptrw();
|
||||||
const FontTexture &ct = p_data->textures[i];
|
for (int32_t i = 0; i < p_data->textures.size(); i++) {
|
||||||
|
if (p_image_format != ct[i].format) {
|
||||||
if (p_image_format != ct.format) {
|
continue;
|
||||||
|
}
|
||||||
|
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
|
ret = ct[i].pack_rect(i, mh, mw);
|
||||||
continue;
|
if (ret.index != -1) {
|
||||||
}
|
|
||||||
|
|
||||||
if (ct.offsets.size() < ct.texture_w) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.y = 0x7fffffff;
|
|
||||||
ret.x = 0;
|
|
||||||
const int *ct_offsets_ptr = ct.offsets.ptr();
|
|
||||||
|
|
||||||
for (int j = 0; j < ct.texture_w - mw; j++) {
|
|
||||||
int max_y = 0;
|
|
||||||
for (int k = j; k < j + mw; k++) {
|
|
||||||
int y = ct_offsets_ptr[k];
|
|
||||||
if (y > max_y) {
|
|
||||||
max_y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_y < ret.y) {
|
|
||||||
ret.y = max_y;
|
|
||||||
ret.x = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
|
|
||||||
continue; // Fail, could not fit it here.
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.index = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret.index == -1) {
|
if (ret.index == -1) {
|
||||||
// Could not find texture to fit, create one.
|
// Could not find texture to fit, create one.
|
||||||
ret.x = 0;
|
|
||||||
ret.y = 0;
|
|
||||||
|
|
||||||
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
|
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
|
||||||
|
|
||||||
#ifdef GDEXTENSION
|
#ifdef GDEXTENSION
|
||||||
@@ -867,12 +836,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture tex;
|
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
|
||||||
tex.texture_w = texsize;
|
|
||||||
tex.texture_h = texsize;
|
|
||||||
tex.format = p_image_format;
|
tex.format = p_image_format;
|
||||||
tex.imgdata.resize(texsize * texsize * p_color_size);
|
tex.imgdata.resize(texsize * texsize * p_color_size);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Zero texture.
|
// Zero texture.
|
||||||
uint8_t *w = tex.imgdata.ptrw();
|
uint8_t *w = tex.imgdata.ptrw();
|
||||||
@@ -895,14 +861,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
|
|||||||
ERR_FAIL_V(ret);
|
ERR_FAIL_V(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tex.offsets.resize(texsize);
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int i = 0; i < texsize; i++) { // Zero offsets.
|
|
||||||
offw[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_data->textures.push_back(tex);
|
p_data->textures.push_back(tex);
|
||||||
ret.index = p_data->textures.size() - 1;
|
|
||||||
|
int32_t idx = p_data->textures.size() - 1;
|
||||||
|
ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1036,7 +998,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
|
|||||||
|
|
||||||
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
|
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
|
||||||
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
||||||
FontTexture &tex = p_data->textures.write[tex_pos.index];
|
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
|
||||||
|
|
||||||
edgeColoringSimple(shape, 3.0); // Max. angle.
|
edgeColoringSimple(shape, 3.0); // Max. angle.
|
||||||
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
|
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
|
||||||
@@ -1079,12 +1041,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
|
|||||||
|
|
||||||
tex.dirty = true;
|
tex.dirty = true;
|
||||||
|
|
||||||
// Update height array.
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
|
|
||||||
offw[k] = tex_pos.y + mh;
|
|
||||||
}
|
|
||||||
|
|
||||||
chr.texture_idx = tex_pos.index;
|
chr.texture_idx = tex_pos.index;
|
||||||
|
|
||||||
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
|
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
|
||||||
@@ -1132,8 +1088,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
|
|||||||
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
||||||
|
|
||||||
// Fit character in char texture.
|
// Fit character in char texture.
|
||||||
|
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
|
||||||
FontTexture &tex = p_data->textures.write[tex_pos.index];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t *wr = tex.imgdata.ptrw();
|
uint8_t *wr = tex.imgdata.ptrw();
|
||||||
@@ -1198,12 +1153,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
|
|||||||
|
|
||||||
tex.dirty = true;
|
tex.dirty = true;
|
||||||
|
|
||||||
// Update height array.
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
|
|
||||||
offw[k] = tex_pos.y + mh;
|
|
||||||
}
|
|
||||||
|
|
||||||
FontGlyph chr;
|
FontGlyph chr;
|
||||||
chr.advance = advance * p_data->scale / p_data->oversampling;
|
chr.advance = advance * p_data->scale / p_data->oversampling;
|
||||||
chr.texture_idx = tex_pos.index;
|
chr.texture_idx = tex_pos.index;
|
||||||
@@ -2492,7 +2441,7 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve
|
|||||||
fd->cache[size]->textures.resize(p_texture_index + 1);
|
fd->cache[size]->textures.resize(p_texture_index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
||||||
|
|
||||||
tex.imgdata = p_image->get_data();
|
tex.imgdata = p_image->get_data();
|
||||||
tex.texture_w = p_image->get_width();
|
tex.texture_w = p_image->get_width();
|
||||||
@@ -2517,11 +2466,12 @@ Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co
|
|||||||
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
|
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
|
||||||
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
|
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
|
||||||
|
|
||||||
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
|
const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
|
||||||
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
|
void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
|
||||||
|
ERR_FAIL_COND(p_offsets.size() % 4 != 0);
|
||||||
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
|
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
|
||||||
ERR_FAIL_COND(!fd);
|
ERR_FAIL_COND(!fd);
|
||||||
|
|
||||||
@@ -2533,8 +2483,11 @@ void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const
|
|||||||
fd->cache[size]->textures.resize(p_texture_index + 1);
|
fd->cache[size]->textures.resize(p_texture_index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
||||||
tex.offsets = p_offset;
|
tex.shelves.clear();
|
||||||
|
for (int32_t i = 0; i < p_offsets.size(); i += 4) {
|
||||||
|
tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
|
PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
|
||||||
@@ -2546,8 +2499,20 @@ PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font
|
|||||||
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
|
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
|
||||||
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
|
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
|
||||||
|
|
||||||
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
|
const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
|
||||||
return tex.offsets;
|
PackedInt32Array ret;
|
||||||
|
ret.resize(tex.shelves.size() * 4);
|
||||||
|
|
||||||
|
int32_t *wr = ret.ptrw();
|
||||||
|
int32_t i = 0;
|
||||||
|
for (const Shelf &E : tex.shelves) {
|
||||||
|
wr[i * 4] = E.x;
|
||||||
|
wr[i * 4 + 1] = E.y;
|
||||||
|
wr[i * 4 + 2] = E.w;
|
||||||
|
wr[i * 4 + 3] = E.h;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
|
PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
|
||||||
@@ -2851,7 +2816,7 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const
|
|||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (gl[p_glyph | mod].texture_idx != -1) {
|
if (gl[p_glyph | mod].texture_idx != -1) {
|
||||||
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -2897,7 +2862,7 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co
|
|||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (gl[p_glyph | mod].texture_idx != -1) {
|
if (gl[p_glyph | mod].texture_idx != -1) {
|
||||||
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -3242,7 +3207,7 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
|
|||||||
#endif
|
#endif
|
||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -3332,7 +3297,7 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
|
|||||||
#endif
|
#endif
|
||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
|
|||||||
@@ -168,20 +168,86 @@ class TextServerAdvanced : public TextServerExtension {
|
|||||||
|
|
||||||
const int rect_range = 1;
|
const int rect_range = 1;
|
||||||
|
|
||||||
struct FontTexture {
|
struct FontTexturePosition {
|
||||||
Image::Format format;
|
int32_t index = -1;
|
||||||
PackedByteArray imgdata;
|
int32_t x = 0;
|
||||||
int texture_w = 0;
|
int32_t y = 0;
|
||||||
int texture_h = 0;
|
|
||||||
PackedInt32Array offsets;
|
FontTexturePosition() {}
|
||||||
Ref<ImageTexture> texture;
|
FontTexturePosition(int32_t p_id, int32_t p_x, int32_t p_y) :
|
||||||
bool dirty = true;
|
index(p_id), x(p_x), y(p_y) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontTexturePosition {
|
struct Shelf {
|
||||||
int index = 0;
|
int32_t x = 0;
|
||||||
int x = 0;
|
int32_t y = 0;
|
||||||
int y = 0;
|
int32_t w = 0;
|
||||||
|
int32_t h = 0;
|
||||||
|
|
||||||
|
FontTexturePosition alloc_shelf(int32_t p_id, int32_t p_w, int32_t p_h) {
|
||||||
|
if (p_w > w || p_h > h) {
|
||||||
|
return FontTexturePosition(-1, 0, 0);
|
||||||
|
}
|
||||||
|
int32_t xx = x;
|
||||||
|
x += p_w;
|
||||||
|
w -= p_w;
|
||||||
|
return FontTexturePosition(p_id, xx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shelf() {}
|
||||||
|
Shelf(int32_t p_x, int32_t p_y, int32_t p_w, int32_t p_h) :
|
||||||
|
x(p_x), y(p_y), w(p_w), h(p_h) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShelfPackTexture {
|
||||||
|
int32_t texture_w = 1024;
|
||||||
|
int32_t texture_h = 1024;
|
||||||
|
|
||||||
|
Image::Format format;
|
||||||
|
PackedByteArray imgdata;
|
||||||
|
Ref<ImageTexture> texture;
|
||||||
|
bool dirty = true;
|
||||||
|
|
||||||
|
List<Shelf> shelves;
|
||||||
|
|
||||||
|
FontTexturePosition pack_rect(int32_t p_id, int32_t p_h, int32_t p_w) {
|
||||||
|
int32_t y = 0;
|
||||||
|
int32_t waste = 0;
|
||||||
|
Shelf *best_shelf = nullptr;
|
||||||
|
int32_t best_waste = std::numeric_limits<std::int32_t>::max();
|
||||||
|
|
||||||
|
for (Shelf &E : shelves) {
|
||||||
|
y += E.h;
|
||||||
|
if (p_w > E.w) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_h == E.h) {
|
||||||
|
return E.alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
if (p_h > E.h) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_h < E.h) {
|
||||||
|
waste = (E.h - p_h) * p_w;
|
||||||
|
if (waste < best_waste) {
|
||||||
|
best_waste = waste;
|
||||||
|
best_shelf = &E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best_shelf) {
|
||||||
|
return best_shelf->alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
if (p_h <= (texture_h - y) && p_w <= texture_w) {
|
||||||
|
List<Shelf>::Element *E = shelves.push_back(Shelf(0, y, texture_w, p_h));
|
||||||
|
return E->get().alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
return FontTexturePosition(-1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShelfPackTexture() {}
|
||||||
|
ShelfPackTexture(int32_t p_w, int32_t p_h) :
|
||||||
|
texture_w(p_w), texture_h(p_h) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontGlyph {
|
struct FontGlyph {
|
||||||
@@ -202,7 +268,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||||||
|
|
||||||
Vector2i size;
|
Vector2i size;
|
||||||
|
|
||||||
Vector<FontTexture> textures;
|
Vector<ShelfPackTexture> textures;
|
||||||
HashMap<int32_t, FontGlyph> glyph_map;
|
HashMap<int32_t, FontGlyph> glyph_map;
|
||||||
HashMap<Vector2i, Vector2> kerning_map;
|
HashMap<Vector2i, Vector2> kerning_map;
|
||||||
hb_font_t *hb_handle = nullptr;
|
hb_font_t *hb_handle = nullptr;
|
||||||
|
|||||||
@@ -211,59 +211,27 @@ String TextServerFallback::_tag_to_name(int64_t p_tag) const {
|
|||||||
|
|
||||||
_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
|
_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
|
||||||
FontTexturePosition ret;
|
FontTexturePosition ret;
|
||||||
ret.index = -1;
|
|
||||||
|
|
||||||
int mw = p_width;
|
int mw = p_width;
|
||||||
int mh = p_height;
|
int mh = p_height;
|
||||||
|
|
||||||
for (int i = 0; i < p_data->textures.size(); i++) {
|
ShelfPackTexture *ct = p_data->textures.ptrw();
|
||||||
const FontTexture &ct = p_data->textures[i];
|
for (int32_t i = 0; i < p_data->textures.size(); i++) {
|
||||||
|
if (p_image_format != ct[i].format) {
|
||||||
if (p_image_format != ct.format) {
|
continue;
|
||||||
|
}
|
||||||
|
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
|
ret = ct[i].pack_rect(i, mh, mw);
|
||||||
continue;
|
if (ret.index != -1) {
|
||||||
}
|
|
||||||
|
|
||||||
if (ct.offsets.size() < ct.texture_w) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.y = 0x7fffffff;
|
|
||||||
ret.x = 0;
|
|
||||||
const int *ct_offsets_ptr = ct.offsets.ptr();
|
|
||||||
|
|
||||||
for (int j = 0; j < ct.texture_w - mw; j++) {
|
|
||||||
int max_y = 0;
|
|
||||||
|
|
||||||
for (int k = j; k < j + mw; k++) {
|
|
||||||
int y = ct_offsets_ptr[k];
|
|
||||||
if (y > max_y) {
|
|
||||||
max_y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_y < ret.y) {
|
|
||||||
ret.y = max_y;
|
|
||||||
ret.x = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
|
|
||||||
continue; // Fail, could not fit it here.
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.index = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret.index == -1) {
|
if (ret.index == -1) {
|
||||||
// Could not find texture to fit, create one.
|
// Could not find texture to fit, create one.
|
||||||
ret.x = 0;
|
|
||||||
ret.y = 0;
|
|
||||||
|
|
||||||
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
|
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
|
||||||
|
|
||||||
#ifdef GDEXTENSION
|
#ifdef GDEXTENSION
|
||||||
@@ -292,12 +260,9 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture tex;
|
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
|
||||||
tex.texture_w = texsize;
|
|
||||||
tex.texture_h = texsize;
|
|
||||||
tex.format = p_image_format;
|
tex.format = p_image_format;
|
||||||
tex.imgdata.resize(texsize * texsize * p_color_size);
|
tex.imgdata.resize(texsize * texsize * p_color_size);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Zero texture.
|
// Zero texture.
|
||||||
uint8_t *w = tex.imgdata.ptrw();
|
uint8_t *w = tex.imgdata.ptrw();
|
||||||
@@ -320,14 +285,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
|
|||||||
ERR_FAIL_V(ret);
|
ERR_FAIL_V(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tex.offsets.resize(texsize);
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int i = 0; i < texsize; i++) { // Zero offsets.
|
|
||||||
offw[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_data->textures.push_back(tex);
|
p_data->textures.push_back(tex);
|
||||||
ret.index = p_data->textures.size() - 1;
|
|
||||||
|
int32_t idx = p_data->textures.size() - 1;
|
||||||
|
ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -461,7 +422,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
|
|||||||
|
|
||||||
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
|
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
|
||||||
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
||||||
FontTexture &tex = p_data->textures.write[tex_pos.index];
|
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
|
||||||
|
|
||||||
edgeColoringSimple(shape, 3.0); // Max. angle.
|
edgeColoringSimple(shape, 3.0); // Max. angle.
|
||||||
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
|
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
|
||||||
@@ -504,12 +465,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
|
|||||||
|
|
||||||
tex.dirty = true;
|
tex.dirty = true;
|
||||||
|
|
||||||
// Update height array.
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
|
|
||||||
offw[k] = tex_pos.y + mh;
|
|
||||||
}
|
|
||||||
|
|
||||||
chr.texture_idx = tex_pos.index;
|
chr.texture_idx = tex_pos.index;
|
||||||
|
|
||||||
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
|
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
|
||||||
@@ -556,8 +511,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
|
|||||||
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
|
||||||
|
|
||||||
// Fit character in char texture.
|
// Fit character in char texture.
|
||||||
|
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
|
||||||
FontTexture &tex = p_data->textures.write[tex_pos.index];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t *wr = tex.imgdata.ptrw();
|
uint8_t *wr = tex.imgdata.ptrw();
|
||||||
@@ -622,12 +576,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
|
|||||||
|
|
||||||
tex.dirty = true;
|
tex.dirty = true;
|
||||||
|
|
||||||
// Update height array.
|
|
||||||
int32_t *offw = tex.offsets.ptrw();
|
|
||||||
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
|
|
||||||
offw[k] = tex_pos.y + mh;
|
|
||||||
}
|
|
||||||
|
|
||||||
FontGlyph chr;
|
FontGlyph chr;
|
||||||
chr.advance = advance * p_data->scale / p_data->oversampling;
|
chr.advance = advance * p_data->scale / p_data->oversampling;
|
||||||
chr.texture_idx = tex_pos.index;
|
chr.texture_idx = tex_pos.index;
|
||||||
@@ -1587,7 +1535,7 @@ void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Ve
|
|||||||
fd->cache[size]->textures.resize(p_texture_index + 1);
|
fd->cache[size]->textures.resize(p_texture_index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
||||||
|
|
||||||
tex.imgdata = p_image->get_data();
|
tex.imgdata = p_image->get_data();
|
||||||
tex.texture_w = p_image->get_width();
|
tex.texture_w = p_image->get_width();
|
||||||
@@ -1612,11 +1560,12 @@ Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, co
|
|||||||
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
|
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
|
||||||
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
|
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
|
||||||
|
|
||||||
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
|
const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
|
||||||
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
|
void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
|
||||||
|
ERR_FAIL_COND(p_offsets.size() % 4 != 0);
|
||||||
FontFallback *fd = font_owner.get_or_null(p_font_rid);
|
FontFallback *fd = font_owner.get_or_null(p_font_rid);
|
||||||
ERR_FAIL_COND(!fd);
|
ERR_FAIL_COND(!fd);
|
||||||
|
|
||||||
@@ -1628,8 +1577,11 @@ void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const
|
|||||||
fd->cache[size]->textures.resize(p_texture_index + 1);
|
fd->cache[size]->textures.resize(p_texture_index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
|
||||||
tex.offsets = p_offset;
|
tex.shelves.clear();
|
||||||
|
for (int32_t i = 0; i < p_offsets.size(); i += 4) {
|
||||||
|
tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
|
PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
|
||||||
@@ -1641,8 +1593,20 @@ PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font
|
|||||||
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
|
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
|
||||||
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
|
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
|
||||||
|
|
||||||
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
|
const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
|
||||||
return tex.offsets;
|
PackedInt32Array ret;
|
||||||
|
ret.resize(tex.shelves.size() * 4);
|
||||||
|
|
||||||
|
int32_t *wr = ret.ptrw();
|
||||||
|
int32_t i = 0;
|
||||||
|
for (const Shelf &E : tex.shelves) {
|
||||||
|
wr[i * 4] = E.x;
|
||||||
|
wr[i * 4 + 1] = E.y;
|
||||||
|
wr[i * 4 + 2] = E.w;
|
||||||
|
wr[i * 4 + 3] = E.h;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
|
PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
|
||||||
@@ -1932,7 +1896,7 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const
|
|||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (gl[p_glyph | mod].texture_idx != -1) {
|
if (gl[p_glyph | mod].texture_idx != -1) {
|
||||||
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -1978,7 +1942,7 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co
|
|||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (gl[p_glyph | mod].texture_idx != -1) {
|
if (gl[p_glyph | mod].texture_idx != -1) {
|
||||||
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -2305,7 +2269,7 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
|
|||||||
#endif
|
#endif
|
||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
@@ -2395,7 +2359,7 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
|
|||||||
#endif
|
#endif
|
||||||
if (RenderingServer::get_singleton() != nullptr) {
|
if (RenderingServer::get_singleton() != nullptr) {
|
||||||
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
|
||||||
FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
|
||||||
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
|
||||||
if (fd->mipmaps) {
|
if (fd->mipmaps) {
|
||||||
img->generate_mipmaps();
|
img->generate_mipmaps();
|
||||||
|
|||||||
@@ -127,20 +127,86 @@ class TextServerFallback : public TextServerExtension {
|
|||||||
|
|
||||||
const int rect_range = 1;
|
const int rect_range = 1;
|
||||||
|
|
||||||
struct FontTexture {
|
struct FontTexturePosition {
|
||||||
Image::Format format;
|
int32_t index = -1;
|
||||||
PackedByteArray imgdata;
|
int32_t x = 0;
|
||||||
int texture_w = 0;
|
int32_t y = 0;
|
||||||
int texture_h = 0;
|
|
||||||
PackedInt32Array offsets;
|
FontTexturePosition() {}
|
||||||
Ref<ImageTexture> texture;
|
FontTexturePosition(int32_t p_id, int32_t p_x, int32_t p_y) :
|
||||||
bool dirty = true;
|
index(p_id), x(p_x), y(p_y) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontTexturePosition {
|
struct Shelf {
|
||||||
int index = 0;
|
int32_t x = 0;
|
||||||
int x = 0;
|
int32_t y = 0;
|
||||||
int y = 0;
|
int32_t w = 0;
|
||||||
|
int32_t h = 0;
|
||||||
|
|
||||||
|
FontTexturePosition alloc_shelf(int32_t p_id, int32_t p_w, int32_t p_h) {
|
||||||
|
if (p_w > w || p_h > h) {
|
||||||
|
return FontTexturePosition(-1, 0, 0);
|
||||||
|
}
|
||||||
|
int32_t xx = x;
|
||||||
|
x += p_w;
|
||||||
|
w -= p_w;
|
||||||
|
return FontTexturePosition(p_id, xx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shelf() {}
|
||||||
|
Shelf(int32_t p_x, int32_t p_y, int32_t p_w, int32_t p_h) :
|
||||||
|
x(p_x), y(p_y), w(p_w), h(p_h) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShelfPackTexture {
|
||||||
|
int32_t texture_w = 1024;
|
||||||
|
int32_t texture_h = 1024;
|
||||||
|
|
||||||
|
Image::Format format;
|
||||||
|
PackedByteArray imgdata;
|
||||||
|
Ref<ImageTexture> texture;
|
||||||
|
bool dirty = true;
|
||||||
|
|
||||||
|
List<Shelf> shelves;
|
||||||
|
|
||||||
|
FontTexturePosition pack_rect(int32_t p_id, int32_t p_h, int32_t p_w) {
|
||||||
|
int32_t y = 0;
|
||||||
|
int32_t waste = 0;
|
||||||
|
Shelf *best_shelf = nullptr;
|
||||||
|
int32_t best_waste = std::numeric_limits<std::int32_t>::max();
|
||||||
|
|
||||||
|
for (Shelf &E : shelves) {
|
||||||
|
y += E.h;
|
||||||
|
if (p_w > E.w) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_h == E.h) {
|
||||||
|
return E.alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
if (p_h > E.h) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p_h < E.h) {
|
||||||
|
waste = (E.h - p_h) * p_w;
|
||||||
|
if (waste < best_waste) {
|
||||||
|
best_waste = waste;
|
||||||
|
best_shelf = &E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best_shelf) {
|
||||||
|
return best_shelf->alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
if (p_h <= (texture_h - y) && p_w <= texture_w) {
|
||||||
|
List<Shelf>::Element *E = shelves.push_back(Shelf(0, y, texture_w, p_h));
|
||||||
|
return E->get().alloc_shelf(p_id, p_w, p_h);
|
||||||
|
}
|
||||||
|
return FontTexturePosition(-1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShelfPackTexture() {}
|
||||||
|
ShelfPackTexture(int32_t p_w, int32_t p_h) :
|
||||||
|
texture_w(p_w), texture_h(p_h) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontGlyph {
|
struct FontGlyph {
|
||||||
@@ -161,7 +227,7 @@ class TextServerFallback : public TextServerExtension {
|
|||||||
|
|
||||||
Vector2i size;
|
Vector2i size;
|
||||||
|
|
||||||
Vector<FontTexture> textures;
|
Vector<ShelfPackTexture> textures;
|
||||||
HashMap<int32_t, FontGlyph> glyph_map;
|
HashMap<int32_t, FontGlyph> glyph_map;
|
||||||
HashMap<Vector2i, Vector2> kerning_map;
|
HashMap<Vector2i, Vector2> kerning_map;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user