diff --git a/core/io/image.cpp b/core/io/image.cpp index 9aa7c9794a2d..e1f37f161f82 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -3300,6 +3300,18 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { _set_color_at_ofs(data.ptrw(), ofs, p_color); } +const uint8_t *Image::ptr() const { + return data.ptr(); +} + +uint8_t *Image::ptrw() { + return data.ptrw(); +} + +int64_t Image::data_size() const { + return data.size(); +} + void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats."); diff --git a/core/io/image.h b/core/io/image.h index be308b0ac173..7cb764c8099b 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -426,6 +426,10 @@ class Image : public Resource { void set_pixelv(const Point2i &p_point, const Color &p_color); void set_pixel(int p_x, int p_y, const Color &p_color); + const uint8_t *ptr() const; + uint8_t *ptrw(); + int64_t data_size() const; + void adjust_bcs(float p_brightness, float p_contrast, float p_saturation); void set_as_black(); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index b4028492c76b..333cc5027bfe 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -807,7 +807,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ ShelfPackTexture *ct = p_data->textures.ptrw(); for (int32_t i = 0; i < p_data->textures.size(); i++) { - if (p_image_format != ct[i].format) { + if (ct[i].image.is_null()) { + continue; + } + if (p_image_format != ct[i].image->get_format()) { continue; } if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture. @@ -838,12 +841,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ } ShelfPackTexture tex = ShelfPackTexture(texsize, texsize); - tex.format = p_image_format; - tex.imgdata.resize(texsize * texsize * p_color_size); + tex.image = Image::create_empty(texsize, texsize, false, p_image_format); { // Zero texture. - uint8_t *w = tex.imgdata.ptrw(); - ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret); + uint8_t *w = tex.image->ptrw(); + ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->data_size(), ret); // Initialize the texture to all-white pixels to prevent artifacts when the // font is displayed at a non-default scale with filtering enabled. if (p_color_size == 2) { @@ -1020,12 +1022,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); { - uint8_t *wr = tex.imgdata.ptrw(); + uint8_t *wr = tex.image->ptrw(); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4; - ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); + ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph()); wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f)); wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f)); @@ -1086,12 +1088,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma ShelfPackTexture &tex = p_data->textures.write[tex_pos.index]; { - uint8_t *wr = tex.imgdata.ptrw(); + uint8_t *wr = tex.image->ptrw(); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size; - ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); + ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph()); switch (bitmap.pixel_mode) { case FT_PIXEL_MODE_MONO: { int byte = i * bitmap.pitch + (j >> 3); @@ -2751,16 +2753,15 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; - tex.imgdata = p_image->get_data(); + tex.image = p_image; tex.texture_w = p_image->get_width(); tex.texture_h = p_image->get_height(); - tex.format = p_image->get_format(); - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = p_image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = p_image->duplicate(); img->generate_mipmaps(); } - tex.texture = ImageTexture::create_from_image(img); tex.dirty = false; } @@ -2775,7 +2776,7 @@ Ref TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref()); 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 tex.image; } void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) { @@ -3144,8 +3145,9 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -3190,8 +3192,9 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -3583,15 +3586,16 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca if (gl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -3693,15 +3697,16 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R if (gl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 6f53ecfa8f22..814a1fbf12f0 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -206,8 +206,7 @@ class TextServerAdvanced : public TextServerExtension { int32_t texture_w = 1024; int32_t texture_h = 1024; - Image::Format format; - PackedByteArray imgdata; + Ref image; Ref texture; bool dirty = true; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index d9689f0441ce..94c5b9b1a1d0 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -242,7 +242,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ ShelfPackTexture *ct = p_data->textures.ptrw(); for (int32_t i = 0; i < p_data->textures.size(); i++) { - if (p_image_format != ct[i].format) { + if (ct[i].image.is_null()) { + continue; + } + if (p_image_format != ct[i].image->get_format()) { continue; } if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture. @@ -274,12 +277,11 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ } ShelfPackTexture tex = ShelfPackTexture(texsize, texsize); - tex.format = p_image_format; - tex.imgdata.resize(texsize * texsize * p_color_size); + tex.image = Image::create_empty(texsize, texsize, false, p_image_format); { // Zero texture. - uint8_t *w = tex.imgdata.ptrw(); - ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret); + uint8_t *w = tex.image->ptrw(); + ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->data_size(), ret); // Initialize the texture to all-white pixels to prevent artifacts when the // font is displayed at a non-default scale with filtering enabled. if (p_color_size == 2) { @@ -456,12 +458,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); { - uint8_t *wr = tex.imgdata.ptrw(); + uint8_t *wr = tex.image->ptrw(); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4; - ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); + ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph()); wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f)); wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f)); @@ -521,12 +523,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma ShelfPackTexture &tex = p_data->textures.write[tex_pos.index]; { - uint8_t *wr = tex.imgdata.ptrw(); + uint8_t *wr = tex.image->ptrw(); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size; - ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); + ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph()); switch (bitmap.pixel_mode) { case FT_PIXEL_MODE_MONO: { int byte = i * bitmap.pitch + (j >> 3); @@ -1745,16 +1747,15 @@ void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Ve ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; - tex.imgdata = p_image->get_data(); + tex.image = p_image; tex.texture_w = p_image->get_width(); tex.texture_h = p_image->get_height(); - tex.format = p_image->get_format(); - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = p_image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = p_image->duplicate(); img->generate_mipmaps(); } - tex.texture = ImageTexture::create_from_image(img); tex.dirty = false; } @@ -1769,7 +1770,7 @@ Ref TextServerFallback::_font_get_texture_image(const RID &p_font_rid, co ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref()); 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 tex.image; } void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) { @@ -2124,8 +2125,9 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -2170,8 +2172,9 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -2518,15 +2521,16 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca if (gl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { @@ -2628,15 +2632,16 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R if (gl.texture_idx != -1) { Color modulate = p_color; #ifdef MODULE_FREETYPE_ENABLED - if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { + if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) { modulate.r = modulate.g = modulate.b = 1.0; } #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - if (fd->mipmaps) { + Ref img = tex.image; + if (fd->mipmaps && !img->has_mipmaps()) { + img = tex.image->duplicate(); img->generate_mipmaps(); } if (tex.texture.is_null()) { diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 74534174b198..9cdf20f3fab9 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -162,8 +162,7 @@ class TextServerFallback : public TextServerExtension { int32_t texture_w = 1024; int32_t texture_h = 1024; - Image::Format format; - PackedByteArray imgdata; + Ref image; Ref texture; bool dirty = true; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index d0ad664c8891..4df7dc99128a 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -1342,7 +1342,7 @@ void FontFile::_get_property_list(List *p_list) const { int tx_cnt = get_texture_count(i, sz); for (int k = 0; k < tx_cnt; k++) { p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); - p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); + p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE)); } PackedInt32Array glyphs = get_glyph_list(i, sz); for (int k = 0; k < glyphs.size(); k++) {