From bcc3643989762a6814f1f0c5a4b63a0e66d6286c Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Fri, 12 Aug 2022 14:03:28 +0300 Subject: [PATCH] Add font LCD sub-pixel anti-aliasing support. --- doc/classes/CanvasItem.xml | 17 ++ doc/classes/EditorSettings.xml | 4 +- doc/classes/FontFile.xml | 4 +- doc/classes/ProjectSettings.xml | 7 +- doc/classes/RenderingDevice.xml | 8 + doc/classes/RenderingServer.xml | 10 + doc/classes/SystemFont.xml | 4 +- doc/classes/TextServer.xml | 46 ++- doc/classes/TextServerExtension.xml | 20 +- drivers/gles3/rasterizer_canvas_gles3.cpp | 155 ++++++---- drivers/gles3/rasterizer_canvas_gles3.h | 3 +- drivers/gles3/shaders/canvas.glsl | 8 +- .../gles3/shaders/canvas_uniforms_inc.glsl | 1 + drivers/gles3/storage/material_storage.h | 1 + drivers/vulkan/rendering_device_vulkan.cpp | 10 + drivers/vulkan/rendering_device_vulkan.h | 1 + editor/editor_fonts.cpp | 82 +++--- editor/editor_property_name_processor.cpp | 1 + editor/editor_settings.cpp | 2 +- .../import/dynamic_font_import_settings.cpp | 16 +- .../import/resource_importer_dynamic_font.cpp | 6 +- editor/import/resource_importer_imagefont.cpp | 2 +- modules/text_server_adv/text_server_adv.cpp | 278 +++++++++++++++--- modules/text_server_adv/text_server_adv.h | 8 +- modules/text_server_fb/text_server_fb.cpp | 266 ++++++++++++++--- modules/text_server_fb/text_server_fb.h | 8 +- scene/main/canvas_item.cpp | 7 + scene/main/canvas_item.h | 1 + scene/register_scene_types.cpp | 10 +- .../resources/default_theme/default_theme.cpp | 4 +- scene/resources/default_theme/default_theme.h | 2 +- scene/resources/font.cpp | 46 +-- scene/resources/font.h | 12 +- servers/rendering/renderer_canvas_cull.cpp | 32 ++ servers/rendering/renderer_canvas_cull.h | 1 + servers/rendering/renderer_canvas_render.h | 3 +- .../renderer_rd/renderer_canvas_render_rd.cpp | 74 ++++- .../renderer_rd/renderer_canvas_render_rd.h | 2 + .../rendering/renderer_rd/shaders/canvas.glsl | 8 +- .../shaders/canvas_uniforms_inc.glsl | 1 + servers/rendering/rendering_device.cpp | 1 + servers/rendering/rendering_device.h | 1 + servers/rendering/rendering_server_default.h | 1 + servers/rendering_server.cpp | 1 + servers/rendering_server.h | 1 + servers/text/text_server_extension.cpp | 16 +- servers/text/text_server_extension.h | 8 +- servers/text_server.cpp | 15 +- servers/text_server.h | 21 +- 49 files changed, 933 insertions(+), 303 deletions(-) diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index fe1fe498d1b..36f49a5a8ee 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -107,6 +107,23 @@ After submitting all animations slices via [method draw_animation_slice], this function can be used to revert drawing to its default state (all subsequent drawing commands will be visible). If you don't care about this particular use case, usage of this function after submitting the slices is not required. + + + + + + + + Draws a textured rectangle region of the font texture with LCD sub-pixel anti-aliasing at a given position, optionally modulated by a color. + Texture is drawn using the following blend operation, blend mode of the [CanvasItemMaterial] is ignored: + [codeblock] + dst.r = texture.r * modulate.r * modulate.a + dst.r * (1.0 - texture.r * modulate.a); + dst.g = texture.g * modulate.g * modulate.a + dst.g * (1.0 - texture.g * modulate.a); + dst.b = texture.b * modulate.b * modulate.a + dst.b * (1.0 - texture.b * modulate.a); + dst.a = modulate.a + dst.a * (1.0 - modulate.a); + [/codeblock] + + diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 033f63c5ce2..5c27a9c6457 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -495,8 +495,8 @@ The language to use for the editor interface. Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url] - - If [code]true[/code], enables FreeType's font antialiasing on the editor fonts. Most fonts are not designed to look good with antialiasing disabled, so it's recommended to leave this enabled unless you're using a pixel art font. + + FreeType's font anti-aliasing mode used to render the editor fonts. Most fonts are not designed to look good with anti-aliasing disabled, so it's recommended to leave this enabled unless you're using a pixel art font. The font hinting mode to use for the editor fonts. FreeType supports the following font hinting modes: diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 0f229ea19a5..4c82ead1dee 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -543,8 +543,8 @@ - - If set to [code]true[/code], font 8-bit anitialiased glyph rendering is supported and enabled. + + Font anti-aliasing mode. Contents of the dynamic font source file. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 0cee71b6139..45b56622d29 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -651,8 +651,8 @@ Path to a custom [Font] resource to use as default for all GUI elements of the project. - - If set to [code]true[/code], default font uses 8-bit anitialiased glyph rendering. See [member FontFile.antialiased]. + + Font anti-aliasing mode. See [member FontFile.antialiasing], If set to [code]true[/code], the default font will have mipmaps generated. This prevents text from looking grainy when a [Control] is scaled down, or when a [Label3D] is viewed from a long distance (if [member Label3D.texture_filter] is set to a mode that displays mipmaps). @@ -672,6 +672,9 @@ + + LCD sub-pixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout]. + Timer setting for incremental search in [Tree], [ItemList], etc. controls (in milliseconds). diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 2f0b9dae72c..718a1613232 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -227,6 +227,14 @@ + + + + + + Sets blend constants for draw list, blend constants are used only if the graphics pipeline is created with [code]DYNAMIC_STATE_BLEND_CONSTANTS[/code] flag set. + + diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 62351ea9ec5..855a55b4e2d 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -176,6 +176,16 @@ + + + + + + + + + + diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml index b7454cc7d2d..c235843f3b8 100644 --- a/doc/classes/SystemFont.xml +++ b/doc/classes/SystemFont.xml @@ -13,8 +13,8 @@ - - If set to [code]true[/code], font 8-bit anitialiased glyph rendering is supported and enabled. + + Font anti-aliasing mode. Array of fallback [Font]s. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index ee3c87b8e68..55d7e8ff2bd 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -98,6 +98,13 @@ [b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update. + + + + + Returns font anti-aliasing mode. + + @@ -447,13 +454,6 @@ Returns [code]true[/code] if a Unicode [param char] is available in the font. - - - - - Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled. - - @@ -556,12 +556,12 @@ Renders the range of characters to the font cache texture. - + - + - If set to [code]true[/code], 8-bit antialiased glyph rendering is used, otherwise 1-bit rendering is used. Used by dynamic fonts only. + Sets font anti-aliasing mode. @@ -1539,6 +1539,32 @@ + + Font glyphs are rasterized as 1-bit bitmaps. + + + Font glyphs are rasterized as 8-bit grayscale anti-aliased bitmaps. + + + Font glyphs are rasterized for LCD screens. + LCD sub-pixel layout is determined by the value of [code]gui/theme/lcd_subpixel_layout[/code] project settings. + LCD sub-pixel anti-aliasing mode is suitable only for rendering horizontal, unscaled text in 2D. + + + Unknown or unsupported sub-pixel layout, LCD sub-pixel anti-aliasing is disabled. + + + Horizontal RGB sub-pixel layout. + + + Horizontal BGR sub-pixel layout. + + + Vertical RGB sub-pixel layout. + + + Vertical BGR sub-pixel layout. + Text direction is determined based on contents and current locale. diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 219052d3d52..cfac266ad24 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -91,6 +91,13 @@ Draws single glyph outline of size [param outline_size] into a canvas item at the position, using [param font_rid] at the size [param size]. + + + + + Returns font anti-aliasing mode. + + @@ -437,13 +444,6 @@ Returns [code]true[/code] if a Unicode [param char] is available in the font. - - - - - Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled. - - @@ -544,12 +544,12 @@ Renders the range of characters to the font cache texture. - + - + - If set to [code]true[/code], 8-bit antialiased glyph rendering is used, otherwise 1-bit rendering is used. Used by dynamic fonts only. + Sets font anti-aliasing mode. diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 28802f571c1..b397d0c665f 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -322,6 +322,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou RID prev_material; uint32_t index = 0; GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX; + Color last_blend_color; GLES3::CanvasShaderData *shader_data_cache = nullptr; state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE); @@ -378,75 +379,13 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX; - if (last_blend_mode != blend_mode) { - if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { - // re-enable it - glEnable(GL_BLEND); - } else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { - // disable it - glDisable(GL_BLEND); - } - - switch (blend_mode) { - case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: { - // Nothing to do here. - - } break; - case GLES3::CanvasShaderData::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (state.transparent_render_target) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - case GLES3::CanvasShaderData::BLEND_MODE_ADD: { - glBlendEquation(GL_FUNC_ADD); - if (state.transparent_render_target) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - - } break; - case GLES3::CanvasShaderData::BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - if (state.transparent_render_target) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - } break; - case GLES3::CanvasShaderData::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (state.transparent_render_target) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - - } break; - case GLES3::CanvasShaderData::BLEND_MODE_PMALPHA: { - glBlendEquation(GL_FUNC_ADD); - if (state.transparent_render_target) { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - } - last_blend_mode = blend_mode; - } - - _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index); + _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index, blend_mode, last_blend_mode, last_blend_color); } // Render last command _render_batch(index); } -void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index) { +void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color) { // Used by Polygon and Mesh. static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP }; @@ -499,6 +438,92 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config + GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode; + Color blend_color; + + if (c->type == Item::Command::TYPE_RECT) { + const Item::CommandRect *rect = static_cast(c); + if (rect->flags & CANVAS_RECT_LCD) { + blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD; + blend_color = rect->modulate; + } + } + + if (r_last_blend_mode != blend_mode || r_last_blend_color != blend_color) { + _render_batch(r_index); + + if (r_last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { + // re-enable it + glEnable(GL_BLEND); + } else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { + // disable it + glDisable(GL_BLEND); + } + + switch (blend_mode) { + case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: { + // Nothing to do here. + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_LCD: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE); + } + glBlendColor(blend_color.r, blend_color.g, blend_color.b, blend_color.a); + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + } break; + case GLES3::CanvasShaderData::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); + } else { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_PMALPHA: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + } break; + } + r_last_blend_mode = blend_mode; + r_last_blend_color = blend_color; + } + switch (c->type) { case Item::Command::TYPE_RECT: { const Item::CommandRect *rect = static_cast(c); @@ -569,6 +594,8 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].msdf[1] = rect->outline; // Outline size. state.instance_data_array[r_index].msdf[2] = 0.f; // Reserved. state.instance_data_array[r_index].msdf[3] = 0.f; // Reserved. + } else if (rect->flags & CANVAS_RECT_LCD) { + state.instance_data_array[r_index].flags |= FLAGS_USE_LCD; } state.instance_data_array[r_index].modulation[0] = rect->modulate.r * base_color.r; diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index f920e37130a..372ac00493d 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -73,6 +73,7 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27), FLAGS_USE_MSDF = (1 << 28), + FLAGS_USE_LCD = (1 << 29), }; enum { @@ -249,7 +250,7 @@ public: void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override; void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false); - void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index); + void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color); void _render_batch(uint32_t &p_max_index); void _bind_instance_data_buffer(uint32_t p_max_index); void _allocate_instance_data_buffer(); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 4df818cd4c9..5ec25327bed 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -473,7 +473,13 @@ void main() { float a = clamp(d * px_size + 0.5, 0.0, 1.0); color.a = a * color.a; } - + } else if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_LCD)) { + vec4 lcd_sample = texture(color_texture, uv); + if (lcd_sample.a == 1.0) { + color.rgb = lcd_sample.rgb * color.a; + } else { + color = vec4(0.0, 0.0, 0.0, 0.0); + } } else { #else { diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl index 852dccf4150..6b61fe9375d 100644 --- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -25,6 +25,7 @@ #define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27) #define FLAGS_USE_MSDF uint(1 << 28) +#define FLAGS_USE_LCD uint(1 << 29) // must be always 128 bytes long struct DrawData { diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index d135357f6a3..a2a7554821b 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -142,6 +142,7 @@ struct CanvasShaderData : public ShaderData { BLEND_MODE_MUL, BLEND_MODE_PMALPHA, BLEND_MODE_DISABLED, + BLEND_MODE_LCD, }; bool valid; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 2debba1b83c..f2d78636d7c 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -7543,6 +7543,16 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL } } +void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + + vkCmdSetBlendConstants(dl->command_buffer, p_color.components); +} + void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 6572de7c52e..6007e1ab4d0 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1155,6 +1155,7 @@ public: virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); + virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color); virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index); virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array); diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index a02051c8ee2..fffe77f1c46 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -37,7 +37,7 @@ #include "scene/resources/default_theme/default_theme.h" #include "scene/resources/font.h" -Ref load_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray *r_fallbacks = nullptr) { +Ref load_external_font(const String &p_path, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray *r_fallbacks = nullptr) { Ref font; font.instantiate(); @@ -45,7 +45,7 @@ Ref load_external_font(const String &p_path, TextServer::Hinting p_hin font->set_data(data); font->set_multichannel_signed_distance_field(p_msdf); - font->set_antialiased(p_aa); + font->set_antialiasing(p_aa); font->set_hinting(p_hinting); font->set_force_autohinter(p_autohint); font->set_subpixel_positioning(p_font_subpixel_positioning); @@ -57,13 +57,13 @@ Ref load_external_font(const String &p_path, TextServer::Hinting p_hin return font; } -Ref load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray *r_fallbacks = nullptr) { +Ref load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray *r_fallbacks = nullptr) { Ref font; font.instantiate(); font->set_data_ptr(p_data, p_size); font->set_multichannel_signed_distance_field(p_msdf); - font->set_antialiased(p_aa); + font->set_antialiasing(p_aa); font->set_hinting(p_hinting); font->set_force_autohinter(p_autohint); font->set_subpixel_positioning(p_font_subpixel_positioning); @@ -91,7 +91,7 @@ Ref make_bold_font(const Ref &p_font, double p_embolden, Ty void editor_register_fonts(Ref p_theme) { Ref dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/font_antialiased"); + TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)EditorSettings::get_singleton()->get("interface/editor/font_antialiasing"); int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting"); TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning"); @@ -123,47 +123,47 @@ void editor_register_fonts(Ref p_theme) { const int default_font_size = int(EDITOR_GET("interface/editor/main_font_size")) * EDSCALE; const float embolden_strength = 0.6; - Ref default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false); - Ref default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + Ref default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false); + Ref default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true); TypedArray fallbacks; - Ref arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); - Ref japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); + Ref japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks); default_font->set_fallbacks(fallbacks); default_font_msdf->set_fallbacks(fallbacks); - Ref default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false); - Ref default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + Ref default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false); + Ref default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true); TypedArray fallbacks_bold; - Ref arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); - Ref thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold); Ref fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold); Ref japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold); default_font_bold->set_fallbacks(fallbacks_bold); default_font_bold_msdf->set_fallbacks(fallbacks_bold); - Ref default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning); default_font_mono->set_fallbacks(fallbacks); // Init base font configs and load custom fonts. @@ -174,7 +174,7 @@ void editor_register_fonts(Ref p_theme) { Ref default_fc; default_fc.instantiate(); if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font); @@ -191,7 +191,7 @@ void editor_register_fonts(Ref p_theme) { Ref default_fc_msdf; default_fc_msdf.instantiate(); if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_msdf); @@ -208,7 +208,7 @@ void editor_register_fonts(Ref p_theme) { Ref bold_fc; bold_fc.instantiate(); if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { - Ref custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_bold); @@ -216,7 +216,7 @@ void editor_register_fonts(Ref p_theme) { } bold_fc->set_base_font(custom_font); } else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_bold); @@ -234,7 +234,7 @@ void editor_register_fonts(Ref p_theme) { Ref bold_fc_msdf; bold_fc_msdf.instantiate(); if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { - Ref custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_bold_msdf); @@ -242,7 +242,7 @@ void editor_register_fonts(Ref p_theme) { } bold_fc_msdf->set_base_font(custom_font); } else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_bold_msdf); @@ -260,7 +260,7 @@ void editor_register_fonts(Ref p_theme) { Ref mono_fc; mono_fc.instantiate(); if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) { - Ref custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning); { TypedArray fallback_custom; fallback_custom.push_back(default_font_mono); diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index 6c713de94a0..c0f823f2131 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -172,6 +172,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["k1"] = "K1"; capitalize_string_remaps["k2"] = "K2"; capitalize_string_remaps["kb"] = "(KB)"; // Unit. + capitalize_string_remaps["lcd"] = "LCD"; capitalize_string_remaps["ldr"] = "LDR"; capitalize_string_remaps["lod"] = "LOD"; capitalize_string_remaps["lowpass"] = "Low-pass"; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 36e64cbd7a6..509488a66af 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -414,7 +414,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 0, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set") _initial_set("interface/editor/code_font_custom_opentype_features", ""); _initial_set("interface/editor/code_font_custom_variations", ""); - _initial_set("interface/editor/font_antialiased", true); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_antialiasing", 1, "None,Grayscale,LCD sub-pixel") #ifdef MACOS_ENABLED EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (None),None,Light,Normal") #else diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 043681aa877..b9be8fb792d 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -449,8 +449,8 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper // Update font preview. if (font_preview.is_valid()) { - if (p_edited_property == "antialiased") { - font_preview->set_antialiased(import_settings_data->get("antialiased")); + if (p_edited_property == "antialiasing") { + font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int()); } else if (p_edited_property == "generate_mipmaps") { font_preview->set_generate_mipmaps(import_settings_data->get("generate_mipmaps")); } else if (p_edited_property == "multichannel_signed_distance_field") { @@ -574,6 +574,12 @@ void DynamicFontImportSettings::_variations_validate() { } } } + if ((TextServer::FontAntialiasing)(int)import_settings_data->get("antialiasing") == TextServer::FONT_ANTIALIASING_LCD) { + warn += "\n" + TTR("Note: LCD sub-pixel anti-aliasing is selected, each of the glyphs will be pre-rendered for all supported sub-pixel layouts (5x)."); + } + if ((TextServer::SubpixelPositioning)(int)import_settings_data->get("subpixel_positioning") != TextServer::SUBPIXEL_POSITIONING_DISABLED) { + warn += "\n" + TTR("Note: Sub-pixel positioning is selected, each of the glyphs might be pre-rendered for multiple sub-pixel offsets (up to 4x)."); + } if (warn.is_empty()) { label_warn->set_text(""); label_warn->hide(); @@ -881,7 +887,7 @@ void DynamicFontImportSettings::_re_import() { HashMap main_settings; main_settings["face_index"] = import_settings_data->get("face_index"); - main_settings["antialiased"] = import_settings_data->get("antialiased"); + main_settings["antialiasing"] = import_settings_data->get("antialiasing"); main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps"); main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field"); main_settings["msdf_pixel_range"] = import_settings_data->get("msdf_pixel_range"); @@ -1079,7 +1085,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { import_settings_data->notify_property_list_changed(); if (font_preview.is_valid()) { - font_preview->set_antialiased(import_settings_data->get("antialiased")); + font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int()); font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); font_preview->set_msdf_size(import_settings_data->get("msdf_size")); @@ -1108,7 +1114,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index 32fd94b093e..c822cd0fecd 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -105,7 +105,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); @@ -139,7 +139,7 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) { Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap &p_options, List *r_platform_variants, List *r_gen_files, Variant *r_metadata) { print_verbose("Importing dynamic font from: " + p_source_file); - bool antialiased = p_options["antialiased"]; + int antialiasing = p_options["antialiasing"]; bool generate_mipmaps = p_options["generate_mipmaps"]; bool msdf = p_options["multichannel_signed_distance_field"]; int px_range = p_options["msdf_pixel_range"]; @@ -159,7 +159,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str Ref font; font.instantiate(); font->set_data(data); - font->set_antialiased(antialiased); + font->set_antialiasing((TextServer::FontAntialiasing)antialiasing); font->set_generate_mipmaps(generate_mipmaps); font->set_multichannel_signed_distance_field(msdf); font->set_msdf_pixel_range(px_range); diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index 374cbe7ce21..58c20610518 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -99,7 +99,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin Ref font; font.instantiate(); - font->set_antialiased(false); + font->set_antialiasing(TextServer::FONT_ANTIALIASING_NONE); font->set_generate_mipmaps(false); font->set_multichannel_signed_distance_field(false); font->set_fixed_size(base_size); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f6180f6c4cc..f91d0b66b31 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -29,12 +29,12 @@ /*************************************************************************/ #include "text_server_adv.h" -#include "core/object/worker_thread_pool.h" #ifdef GDEXTENSION // Headers for building as GDExtension plug-in. #include +#include #include #include #include @@ -44,8 +44,10 @@ using namespace godot; #else // Headers for building as built-in module. +#include "core/config/project_settings.h" #include "core/core_bind.h" #include "core/error/error_macros.h" +#include "core/object/worker_thread_pool.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -791,6 +793,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; + if (p_image_format != ct.format) { + continue; + } + if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -1082,9 +1088,28 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( #endif #ifdef MODULE_FREETYPE_ENABLED -_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const { +_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const { int w = bitmap.width; int h = bitmap.rows; + int color_size = 2; + + switch (bitmap.pixel_mode) { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: { + color_size = 2; + } break; + case FT_PIXEL_MODE_BGRA: { + color_size = 4; + } break; + case FT_PIXEL_MODE_LCD: { + color_size = 4; + w /= 3; + } break; + case FT_PIXEL_MODE_LCD_V: { + color_size = 4; + h /= 3; + } break; + } int mw = w + p_rect_margin * 4; int mh = h + p_rect_margin * 4; @@ -1092,7 +1117,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); - int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false); @@ -1127,6 +1151,34 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; wr[ofs + 3] = bitmap.buffer[ofs_color + 3]; } break; + case FT_PIXEL_MODE_LCD: { + int ofs_color = i * bitmap.pitch + (j * 3); + if (p_bgra) { + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 3] = 255; + } else { + wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 3] = 255; + } + } break; + case FT_PIXEL_MODE_LCD_V: { + int ofs_color = i * bitmap.pitch * 3 + j; + if (p_bgra) { + wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2]; + wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 3] = 255; + } else { + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch]; + wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2]; + wr[ofs + 3] = 255; + } + } break; default: ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + "."); break; @@ -1230,9 +1282,44 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, FT_Outline_Transform(&fd->face->glyph->outline, &mat); } + FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL; + bool bgra = false; + switch (p_font_data->antialiasing) { + case FONT_ANTIALIASING_NONE: { + aa_mode = FT_RENDER_MODE_MONO; + } break; + case FONT_ANTIALIASING_GRAY: { + aa_mode = FT_RENDER_MODE_NORMAL; + } break; + case FONT_ANTIALIASING_LCD: { + int aa_layout = (int)((p_glyph >> 24) & 7); + switch (aa_layout) { + case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: { + aa_mode = FT_RENDER_MODE_LCD; + bgra = false; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: { + aa_mode = FT_RENDER_MODE_LCD; + bgra = true; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: { + aa_mode = FT_RENDER_MODE_LCD_V; + bgra = false; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: { + aa_mode = FT_RENDER_MODE_LCD_V; + bgra = true; + } break; + default: { + aa_mode = FT_RENDER_MODE_NORMAL; + } break; + } + } break; + } + if (!outline) { if (!p_font_data->msdf) { - error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); + error = FT_Render_Glyph(fd->face->glyph, aa_mode); } FT_GlyphSlot slot = fd->face->glyph; if (!error) { @@ -1244,7 +1331,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!"); #endif } else { - gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0); + gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra); } } } else { @@ -1264,11 +1351,11 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) { goto cleanup_glyph; } - if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) { + if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) { goto cleanup_glyph; } glyph_bitmap = (FT_BitmapGlyph)glyph; - gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2()); + gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra); cleanup_glyph: FT_Done_Glyph(glyph); @@ -1925,23 +2012,23 @@ String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { return fd->font_name; } -void TextServerAdvanced::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) { +void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->antialiased != p_antialiased) { + if (fd->antialiasing != p_antialiasing) { _font_clear_cache(fd); - fd->antialiased = p_antialiased; + fd->antialiasing = p_antialiasing; } } -bool TextServerAdvanced::font_is_antialiased(const RID &p_font_rid) const { +TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, false); + ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE); MutexLock lock(fd->mutex); - return fd->antialiased; + return fd->antialiasing; } void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { @@ -2514,7 +2601,16 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_ Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2557,7 +2653,16 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2593,7 +2698,16 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2629,7 +2743,16 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Rect2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2660,7 +2783,16 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return -1; // Invalid or non graphicl glyph, do not display errors. } @@ -2691,7 +2823,16 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return RID(); // Invalid or non graphicl glyph, do not display errors. } @@ -2730,7 +2871,16 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Size2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2986,16 +3136,18 @@ void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i if (fd->msdf) { _ensure_glyph(fd, size, (int32_t)idx); } else { - if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); - } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - } else { - _ensure_glyph(fd, size, (int32_t)idx); + for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + } else { + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + } } } } @@ -3016,16 +3168,18 @@ void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i if (fd->msdf) { _ensure_glyph(fd, size, (int32_t)idx); } else { - if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); - } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - } else { - _ensure_glyph(fd, size, (int32_t)idx); + for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + } else { + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + } } } } @@ -3041,9 +3195,19 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED if (!fd->msdf && fd->cache[size]->face) { + // LCD layout, bits 24, 25, 26 + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + lcd_aa = true; + index = index | (layout << 24); + } + } + // Subpixel X-shift, bits 27, 28 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); index = index | (xshift << 27); @@ -3065,7 +3229,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can 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) { + if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa) { modulate.r = modulate.g = modulate.b = 1.0; } #endif @@ -3103,7 +3267,11 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can } cpos += gl.rect.position; Size2 csize = gl.rect.size; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + if (lcd_aa) { + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + } else { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + } } } } @@ -3119,9 +3287,19 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED if (!fd->msdf && fd->cache[size]->face) { + // LCD layout, bits 24, 25, 26 + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + lcd_aa = true; + index = index | (layout << 24); + } + } + // Subpixel X-shift, bits 27, 28 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); index = index | (xshift << 27); @@ -3181,7 +3359,11 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI } cpos += gl.rect.position; Size2 csize = gl.rect.size; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + if (lcd_aa) { + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + } else { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + } } } } @@ -4947,6 +5129,14 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count); + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + // Process glyphs. if (glyph_count > 0) { Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph)); @@ -5000,7 +5190,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star gl.index = glyph_info[i].codepoint; if (gl.index != 0) { - _ensure_glyph(fd, fss, gl.index); + _ensure_glyph(fd, fss, gl.index | mod); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { if (subpos) { gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 7ae329d6160..ff8060151db 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -223,7 +223,7 @@ class TextServerAdvanced : public TextServerExtension { struct FontAdvanced { Mutex mutex; - bool antialiased = true; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; bool mipmaps = false; bool msdf = false; int msdf_range = 14; @@ -271,7 +271,7 @@ class TextServerAdvanced : public TextServerExtension { _FORCE_INLINE_ FontGlyph rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const; #endif #ifdef MODULE_FREETYPE_ENABLED - _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const; + _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const; #endif _FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; _FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const; @@ -498,8 +498,8 @@ public: virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; virtual String font_get_name(const RID &p_font_rid) const override; - virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override; - virtual bool font_is_antialiased(const RID &p_font_rid) const override; + virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; + virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 3f5041234c3..6fae75f49cd 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -34,6 +34,7 @@ // Headers for building as GDExtension plug-in. #include +#include #include #include #include @@ -43,6 +44,7 @@ using namespace godot; #else // Headers for building as built-in module. +#include "core/config/project_settings.h" #include "core/error/error_macros.h" #include "core/string/print_string.h" #include "core/string/ucaps.h" @@ -209,6 +211,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; + if (p_image_format != ct.format) { + continue; + } + if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -500,9 +506,28 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( #endif #ifdef MODULE_FREETYPE_ENABLED -_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const { +_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const { int w = bitmap.width; int h = bitmap.rows; + int color_size = 2; + + switch (bitmap.pixel_mode) { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: { + color_size = 2; + } break; + case FT_PIXEL_MODE_BGRA: { + color_size = 4; + } break; + case FT_PIXEL_MODE_LCD: { + color_size = 4; + w /= 3; + } break; + case FT_PIXEL_MODE_LCD_V: { + color_size = 4; + h /= 3; + } break; + } int mw = w + p_rect_margin * 4; int mh = h + p_rect_margin * 4; @@ -510,7 +535,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); - int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false); @@ -545,6 +569,34 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; wr[ofs + 3] = bitmap.buffer[ofs_color + 3]; } break; + case FT_PIXEL_MODE_LCD: { + int ofs_color = i * bitmap.pitch + (j * 3); + if (p_bgra) { + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 3] = 255; + } else { + wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 3] = 255; + } + } break; + case FT_PIXEL_MODE_LCD_V: { + int ofs_color = i * bitmap.pitch * 3 + j; + if (p_bgra) { + wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2]; + wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 3] = 255; + } else { + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch]; + wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2]; + wr[ofs + 3] = 255; + } + } break; default: ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + "."); break; @@ -650,9 +702,44 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, FT_Outline_Transform(&fd->face->glyph->outline, &mat); } + FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL; + bool bgra = false; + switch (p_font_data->antialiasing) { + case FONT_ANTIALIASING_NONE: { + aa_mode = FT_RENDER_MODE_MONO; + } break; + case FONT_ANTIALIASING_GRAY: { + aa_mode = FT_RENDER_MODE_NORMAL; + } break; + case FONT_ANTIALIASING_LCD: { + int aa_layout = (int)((p_glyph >> 24) & 7); + switch (aa_layout) { + case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: { + aa_mode = FT_RENDER_MODE_LCD; + bgra = false; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: { + aa_mode = FT_RENDER_MODE_LCD; + bgra = true; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: { + aa_mode = FT_RENDER_MODE_LCD_V; + bgra = false; + } break; + case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: { + aa_mode = FT_RENDER_MODE_LCD_V; + bgra = true; + } break; + default: { + aa_mode = FT_RENDER_MODE_NORMAL; + } break; + } + } break; + } + if (!outline) { if (!p_font_data->msdf) { - error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); + error = FT_Render_Glyph(fd->face->glyph, aa_mode); } FT_GlyphSlot slot = fd->face->glyph; if (!error) { @@ -664,7 +751,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!"); #endif } else { - gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0); + gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra); } } } else { @@ -684,11 +771,11 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) { goto cleanup_glyph; } - if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) { + if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) { goto cleanup_glyph; } glyph_bitmap = (FT_BitmapGlyph)glyph; - gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2()); + gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra); cleanup_glyph: FT_Done_Glyph(glyph); @@ -1014,23 +1101,23 @@ String TextServerFallback::font_get_name(const RID &p_font_rid) const { return fd->font_name; } -void TextServerFallback::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) { +void TextServerFallback::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->antialiased != p_antialiased) { + if (fd->antialiasing != p_antialiasing) { _font_clear_cache(fd); - fd->antialiased = p_antialiased; + fd->antialiasing = p_antialiasing; } } -bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const { +TextServer::FontAntialiasing TextServerFallback::font_get_antialiasing(RID p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, false); + ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE); MutexLock lock(fd->mutex); - return fd->antialiased; + return fd->antialiasing; } void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { @@ -1589,7 +1676,16 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_ Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -1632,7 +1728,16 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -1668,7 +1773,16 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Vector2(); // Invalid or non graphicl glyph, do not display errors. } @@ -1704,7 +1818,16 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Rect2(); // Invalid or non graphicl glyph, do not display errors. } @@ -1735,7 +1858,16 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return -1; // Invalid or non graphicl glyph, do not display errors. } @@ -1766,7 +1898,16 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return RID(); // Invalid or non graphicl glyph, do not display errors. } @@ -1805,7 +1946,16 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); - if (!_ensure_glyph(fd, size, p_glyph)) { + + int mod = 0; + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + mod = (layout << 24); + } + } + + if (!_ensure_glyph(fd, size, p_glyph | mod)) { return Size2(); // Invalid or non graphicl glyph, do not display errors. } @@ -2043,16 +2193,18 @@ void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i if (fd->msdf) { _ensure_glyph(fd, size, (int32_t)idx); } else { - if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); - } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - } else { - _ensure_glyph(fd, size, (int32_t)idx); + for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + } else { + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + } } } } @@ -2073,16 +2225,18 @@ void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i if (fd->msdf) { _ensure_glyph(fd, size, (int32_t)idx); } else { - if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); - } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); - _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); - } else { - _ensure_glyph(fd, size, (int32_t)idx); + for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24)); + } else { + _ensure_glyph(fd, size, (int32_t)idx | (aa << 24)); + } } } } @@ -2098,9 +2252,19 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED if (!fd->msdf && fd->cache[size]->face) { + // LCD layout, bits 24, 25, 26 + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + lcd_aa = true; + index = index | (layout << 24); + } + } + // Subpixel X-shift, bits 27, 28 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); index = index | (xshift << 27); @@ -2122,7 +2286,7 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can 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) { + if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa) { modulate.r = modulate.g = modulate.b = 1.0; } #endif @@ -2160,7 +2324,11 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can } cpos += gl.rect.position; Size2 csize = gl.rect.size; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + if (lcd_aa) { + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + } else { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + } } } } @@ -2176,9 +2344,19 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + bool lcd_aa = false; #ifdef MODULE_FREETYPE_ENABLED if (!fd->msdf && fd->cache[size]->face) { + // LCD layout, bits 24, 25, 26 + if (fd->antialiasing == FONT_ANTIALIASING_LCD) { + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { + lcd_aa = true; + index = index | (layout << 24); + } + } + // Subpixel X-shift, bits 27, 28 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); index = index | (xshift << 27); @@ -2238,7 +2416,11 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI } cpos += gl.rect.position; Size2 csize = gl.rect.size; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + if (lcd_aa) { + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate); + } else { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); + } } } } diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index fef19d442bd..e1609ef500e 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -179,7 +179,7 @@ class TextServerFallback : public TextServerExtension { struct FontFallback { Mutex mutex; - bool antialiased = true; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; bool mipmaps = false; bool msdf = false; int msdf_range = 14; @@ -225,7 +225,7 @@ class TextServerFallback : public TextServerExtension { _FORCE_INLINE_ FontGlyph rasterize_msdf(FontFallback *p_font_data, FontForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const; #endif #ifdef MODULE_FREETYPE_ENABLED - _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const; + _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const; #endif _FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; _FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const; @@ -378,8 +378,8 @@ public: virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; virtual String font_get_name(const RID &p_font_rid) const override; - virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override; - virtual bool font_is_antialiased(const RID &p_font_rid) const override; + virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; + virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index ce204c6aeb5..1bc0daef997 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -587,6 +587,12 @@ void CanvasItem::draw_msdf_texture_rect_region(const Ref &p_texture, RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range); } +void CanvasItem::draw_lcd_texture_rect_region(const Ref &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) { + ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL_COND(p_texture.is_null()); + RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate); +} + void CanvasItem::draw_style_box(const Ref &p_style_box, const Rect2 &p_rect) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); @@ -919,6 +925,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0)); + ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box); ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref()), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref())); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 38e0be1683f..1e0d4552ce7 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -226,6 +226,7 @@ public: void draw_texture_rect(const Ref &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void draw_texture_rect_region(const Ref &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); void draw_msdf_texture_rect_region(const Ref &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0); + void draw_lcd_texture_rect_region(const Ref &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void draw_style_box(const Ref &p_style_box, const Rect2 &p_rect); void draw_primitive(const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, Ref p_texture = Ref(), real_t p_width = 1); void draw_polygon(const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), Ref p_texture = Ref()); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 762d9f2a28f..265ee04bc8e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -1130,8 +1130,8 @@ void initialize_theme() { String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - bool font_antialiased = (bool)GLOBAL_DEF_RST("gui/theme/default_font_antialiased", true); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiased", PropertyInfo(Variant::BOOL, "gui/theme/default_font_antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); @@ -1142,6 +1142,10 @@ void initialize_theme() { const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false); const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false); + GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR")); + ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false); + Ref font; if (!font_path.is_empty()) { font = ResourceLoader::load(font_path); @@ -1152,7 +1156,7 @@ void initialize_theme() { // Always make the default theme to avoid invalid default font/icon/style in the given theme. if (RenderingServer::get_singleton()) { - make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiased, font_msdf, font_generate_mipmaps); + make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps); } if (!theme_path.is_empty()) { diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index b96ee5c6c46..55325979e2b 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1053,7 +1053,7 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2); } -void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, bool p_font_antialiased, bool p_font_msdf, bool p_font_generate_mipmaps) { +void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, TextServer::FontAntialiasing p_font_antialiasing, bool p_font_msdf, bool p_font_generate_mipmaps) { Ref t; t.instantiate(); @@ -1077,7 +1077,7 @@ void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPos dynamic_font->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size); dynamic_font->set_subpixel_positioning(p_font_subpixel); dynamic_font->set_hinting(p_font_hinting); - dynamic_font->set_antialiased(p_font_antialiased); + dynamic_font->set_antialiasing(p_font_antialiasing); dynamic_font->set_multichannel_signed_distance_field(p_font_msdf); dynamic_font->set_generate_mipmaps(p_font_generate_mipmaps); diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 9b070a90cca..15be5e676f8 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -36,7 +36,7 @@ const int default_font_size = 16; void fill_default_theme(Ref &theme, const Ref &default_font, const Ref &bold_font, const Ref &bold_italics_font, const Ref &italics_font, Ref &default_icon, Ref &default_style, float p_scale); -void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, bool p_font_antialiased = true, bool p_font_msdf = false, bool p_font_generate_mipmaps = false); +void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false); void clear_default_theme(); #endif // DEFAULT_THEME_H diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index e7d5d40777f..be8e4cef7c7 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -576,7 +576,7 @@ _FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const { if (unlikely(!cache[p_cache_index].is_valid())) { cache.write[p_cache_index] = TS->create_font(); TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size); - TS->font_set_antialiased(cache[p_cache_index], antialiased); + TS->font_set_antialiasing(cache[p_cache_index], antialiasing); TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps); TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf); TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range); @@ -875,8 +875,8 @@ void FontFile::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name); ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style); - ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontFile::set_antialiased); - ClassDB::bind_method(D_METHOD("is_antialiased"), &FontFile::is_antialiased); + ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &FontFile::set_antialiasing); + ClassDB::bind_method(D_METHOD("get_antialiasing"), &FontFile::get_antialiasing); ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontFile::set_generate_mipmaps); ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontFile::get_generate_mipmaps); @@ -996,7 +996,7 @@ void FontFile::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic,Fixed Size", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style"); @@ -1318,7 +1318,7 @@ void FontFile::reset_state() { data_size = 0; cache.clear(); - antialiased = true; + antialiasing = TextServer::FONT_ANTIALIASING_GRAY; mipmaps = false; msdf = false; force_autohinter = false; @@ -1337,7 +1337,7 @@ void FontFile::reset_state() { Error FontFile::load_bitmap_font(const String &p_path) { reset_state(); - antialiased = false; + antialiasing = TextServer::FONT_ANTIALIASING_NONE; mipmaps = false; msdf = false; force_autohinter = false; @@ -1864,19 +1864,19 @@ void FontFile::set_font_style(BitField p_style) { TS->font_set_style(cache[0], p_style); } -void FontFile::set_antialiased(bool p_antialiased) { - if (antialiased != p_antialiased) { - antialiased = p_antialiased; +void FontFile::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) { + if (antialiasing != p_antialiasing) { + antialiasing = p_antialiasing; for (int i = 0; i < cache.size(); i++) { _ensure_rid(i); - TS->font_set_antialiased(cache[i], antialiased); + TS->font_set_antialiasing(cache[i], antialiasing); } emit_changed(); } } -bool FontFile::is_antialiased() const { - return antialiased; +TextServer::FontAntialiasing FontFile::get_antialiasing() const { + return antialiasing; } void FontFile::set_generate_mipmaps(bool p_generate_mipmaps) { @@ -2699,8 +2699,8 @@ FontVariation::~FontVariation() { /*************************************************************************/ void SystemFont::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &SystemFont::set_antialiased); - ClassDB::bind_method(D_METHOD("is_antialiased"), &SystemFont::is_antialiased); + ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &SystemFont::set_antialiasing); + ClassDB::bind_method(D_METHOD("get_antialiasing"), &SystemFont::get_antialiasing); ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &SystemFont::set_generate_mipmaps); ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &SystemFont::get_generate_mipmaps); @@ -2727,7 +2727,7 @@ void SystemFont::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "font_names"), "set_font_names", "get_font_names"); ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic"), "set_font_style", "get_font_style"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "is_antialiased"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "get_generate_mipmaps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); @@ -2804,7 +2804,7 @@ void SystemFont::_update_base_font() { } // Apply font rendering settings. - file->set_antialiased(antialiased); + file->set_antialiasing(antialiasing); file->set_generate_mipmaps(mipmaps); file->set_force_autohinter(force_autohinter); file->set_hinting(hinting); @@ -2841,7 +2841,7 @@ void SystemFont::reset_state() { ftr_weight = 0; ftr_italic = 0; style = 0; - antialiased = true; + antialiasing = TextServer::FONT_ANTIALIASING_GRAY; mipmaps = false; force_autohinter = false; hinting = TextServer::HINTING_LIGHT; @@ -2907,18 +2907,18 @@ Ref SystemFont::_get_base_font_or_default() const { return Ref(); } -void SystemFont::set_antialiased(bool p_antialiased) { - if (antialiased != p_antialiased) { - antialiased = p_antialiased; +void SystemFont::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) { + if (antialiasing != p_antialiasing) { + antialiasing = p_antialiasing; if (base_font.is_valid()) { - base_font->set_antialiased(antialiased); + base_font->set_antialiasing(antialiasing); } emit_changed(); } } -bool SystemFont::is_antialiased() const { - return antialiased; +TextServer::FontAntialiasing SystemFont::get_antialiasing() const { + return antialiasing; } void SystemFont::set_generate_mipmaps(bool p_generate_mipmaps) { diff --git a/scene/resources/font.h b/scene/resources/font.h index 696152a23b4..75482400f30 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -141,7 +141,7 @@ class FontFile : public Font { size_t data_size = 0; PackedByteArray data; - bool antialiased = true; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; bool mipmaps = false; bool msdf = false; int msdf_pixel_range = 16; @@ -192,8 +192,8 @@ public: virtual void set_font_style_name(const String &p_name); virtual void set_font_style(BitField p_style); - virtual void set_antialiased(bool p_antialiased); - virtual bool is_antialiased() const; + virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing); + virtual TextServer::FontAntialiasing get_antialiasing() const; virtual void set_generate_mipmaps(bool p_generate_mipmaps); virtual bool get_generate_mipmaps() const; @@ -398,7 +398,7 @@ class SystemFont : public Font { int ftr_weight = 0; int ftr_italic = 0; - bool antialiased = true; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; bool mipmaps = false; bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; @@ -417,8 +417,8 @@ protected: public: virtual Ref _get_base_font_or_default() const; - virtual void set_antialiased(bool p_antialiased); - virtual bool is_antialiased() const; + virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing); + virtual TextServer::FontAntialiasing get_antialiasing() const; virtual void set_generate_mipmaps(bool p_generate_mipmaps); virtual bool get_generate_mipmaps() const; diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 86e5e4802bc..aa9772a4833 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1183,6 +1183,38 @@ void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, co rect->px_range = p_px_range; } +void RendererCanvasCull::canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_COND(!canvas_item); + + Item::CommandRect *rect = canvas_item->alloc_command(); + ERR_FAIL_COND(!rect); + rect->modulate = p_modulate; + rect->rect = p_rect; + + rect->texture = p_texture; + + rect->source = p_src_rect; + rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_LCD; + + if (p_rect.size.x < 0) { + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H; + rect->rect.size.x = -rect->rect.size.x; + } + if (p_src_rect.size.x < 0) { + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H; + rect->source.size.x = -rect->source.size.x; + } + if (p_rect.size.y < 0) { + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V; + rect->rect.size.y = -rect->rect.size.y; + } + if (p_src_rect.size.y < 0) { + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V; + rect->source.size.y = -rect->source.size.y; + } +} + void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index e8c54310c97..0d6a4006f86 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -225,6 +225,7 @@ public: void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0); + void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)); void canvas_item_add_primitive(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, RID p_texture, float p_width = 1.0); void canvas_item_add_polygon(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), RID p_texture = RID()); diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 11a7d342911..6791ed96267 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -46,6 +46,7 @@ public: CANVAS_RECT_CLIP_UV = 32, CANVAS_RECT_IS_GROUP = 64, CANVAS_RECT_MSDF = 128, + CANVAS_RECT_LCD = 256, }; struct Light { @@ -193,7 +194,7 @@ public: Rect2 rect; Color modulate; Rect2 source; - uint8_t flags; + uint16_t flags; float outline; float px_range; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 38a2340d403..937585c98be 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -494,7 +494,11 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend } //bind pipeline - { + if (rect->flags & CANVAS_RECT_LCD) { + RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD_LCD_BLEND].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, rect->modulate); + } else { RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); } @@ -556,6 +560,8 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.msdf[1] = rect->outline; // Outline size. push_constant.msdf[2] = 0.f; // Reserved. push_constant.msdf[3] = 0.f; // Reserved. + } else if (rect->flags & CANVAS_RECT_LCD) { + push_constant.flags |= FLAGS_USE_LCD; } push_constant.modulation[0] = rect->modulate.r * base_color.r; @@ -2113,6 +2119,18 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { RD::PipelineColorBlendState blend_state; blend_state.attachments.push_back(attachment); + RD::PipelineColorBlendState::Attachment attachment_lcd; + attachment_lcd.enable_blend = true; + attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD; + attachment_lcd.color_blend_op = RD::BLEND_OP_ADD; + attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR; + attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + RD::PipelineColorBlendState blend_state_lcd; + blend_state_lcd.attachments.push_back(attachment_lcd); + //update pipelines for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) { @@ -2128,10 +2146,12 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_LINESTRIPS, RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_TRIANGLES, }; ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = { - { //non lit + { + //non lit SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, SHADER_VARIANT_PRIMITIVE, @@ -2141,8 +2161,11 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES, - SHADER_VARIANT_ATTRIBUTES_POINTS }, - { //lit + SHADER_VARIANT_ATTRIBUTES_POINTS, + SHADER_VARIANT_QUAD, + }, + { + //lit SHADER_VARIANT_QUAD_LIGHT, SHADER_VARIANT_NINEPATCH_LIGHT, SHADER_VARIANT_PRIMITIVE_LIGHT, @@ -2152,11 +2175,17 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, - SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT }, + SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT, + SHADER_VARIANT_QUAD_LIGHT, + }, }; RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]); - pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) { + pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS); + } else { + pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + } } } @@ -2363,6 +2392,18 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { blend_state.attachments.push_back(blend_attachment); + RD::PipelineColorBlendState::Attachment attachment_lcd; + attachment_lcd.enable_blend = true; + attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD; + attachment_lcd.color_blend_op = RD::BLEND_OP_ADD; + attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR; + attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + RD::PipelineColorBlendState blend_state_lcd; + blend_state_lcd.attachments.push_back(attachment_lcd); + for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) { for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) { RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { @@ -2376,10 +2417,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_LINESTRIPS, RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_TRIANGLES, }; ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = { - { //non lit + { + //non lit SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, SHADER_VARIANT_PRIMITIVE, @@ -2389,8 +2432,11 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES, - SHADER_VARIANT_ATTRIBUTES_POINTS }, - { //lit + SHADER_VARIANT_ATTRIBUTES_POINTS, + SHADER_VARIANT_QUAD, + }, + { + //lit SHADER_VARIANT_QUAD_LIGHT, SHADER_VARIANT_NINEPATCH_LIGHT, SHADER_VARIANT_PRIMITIVE_LIGHT, @@ -2400,11 +2446,17 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, - SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT }, + SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT, + SHADER_VARIANT_QUAD_LIGHT, + }, }; RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]); - shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) { + shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS); + } else { + shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + } } } } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index bcbbbaa1a07..54077a5b9ad 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -85,6 +85,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27), FLAGS_USE_MSDF = (1 << 28), + FLAGS_USE_LCD = (1 << 29), }; enum { @@ -122,6 +123,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_POINTS, + PIPELINE_VARIANT_QUAD_LCD_BLEND, PIPELINE_VARIANT_MAX }; enum PipelineLightMode { diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index f8e9020f9fc..459d798a802 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -509,7 +509,13 @@ void main() { float a = clamp(d * px_size + 0.5, 0.0, 1.0); color.a = a * color.a; } - + } else if (bool(draw_data.flags & FLAGS_USE_LCD)) { + vec4 lcd_sample = texture(sampler2D(color_texture, texture_sampler), uv); + if (lcd_sample.a == 1.0) { + color.rgb = lcd_sample.rgb * color.a; + } else { + color = vec4(0.0, 0.0, 0.0, 0.0); + } } else { #else { diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 2ea6965c09f..1b627a3e812 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -25,6 +25,7 @@ #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) #define FLAGS_USE_MSDF (1 << 28) +#define FLAGS_USE_LCD (1 << 29) #define SAMPLER_NEAREST_CLAMP 0 #define SAMPLER_LINEAR_CLAMP 1 diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index c07a783302e..2fefdbff524 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -429,6 +429,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray())); ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray())); + ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants); ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline); ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("draw_list_bind_vertex_array", "draw_list", "vertex_array"), &RenderingDevice::draw_list_bind_vertex_array); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index a864cfa74c0..6dadcab3836 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1129,6 +1129,7 @@ public: virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()) = 0; virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()) = 0; + virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) = 0; virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0; virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0; virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index cc79d095037..9b174d5879a 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -831,6 +831,7 @@ public: FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool) FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool) FUNC7(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float) + FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &) FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &) FUNC6(canvas_item_add_primitive, RID, const Vector &, const Vector &, const Vector &, RID, float) FUNC5(canvas_item_add_polygon, RID, const Vector &, const Vector &, const Vector &, RID) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index bbe78236b50..cba75effc9b 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2579,6 +2579,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0)); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index d04c62bfd28..572b08092e2 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1323,6 +1323,7 @@ public: virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0; virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false) = 0; virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0) = 0; + virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0; virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0; virtual void canvas_item_add_primitive(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, RID p_texture, float p_width = 1.0) = 0; virtual void canvas_item_add_polygon(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), RID p_texture = RID()) = 0; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 59310ab69bf..23bd0e8936b 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -69,8 +69,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(font_set_style_name, "font_rid", "name_style"); GDVIRTUAL_BIND(font_get_style_name, "font_rid"); - GDVIRTUAL_BIND(font_set_antialiased, "font_rid", "antialiased"); - GDVIRTUAL_BIND(font_is_antialiased, "font_rid"); + GDVIRTUAL_BIND(font_set_antialiasing, "font_rid", "antialiasing"); + GDVIRTUAL_BIND(font_get_antialiasing, "font_rid"); GDVIRTUAL_BIND(font_set_generate_mipmaps, "font_rid", "generate_mipmaps"); GDVIRTUAL_BIND(font_get_generate_mipmaps, "font_rid"); @@ -478,16 +478,16 @@ String TextServerExtension::font_get_name(const RID &p_font_rid) const { return String(); } -void TextServerExtension::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) { - GDVIRTUAL_CALL(font_set_antialiased, p_font_rid, p_antialiased); +void TextServerExtension::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { + GDVIRTUAL_CALL(font_set_antialiasing, p_font_rid, p_antialiasing); } -bool TextServerExtension::font_is_antialiased(const RID &p_font_rid) const { - bool ret; - if (GDVIRTUAL_CALL(font_is_antialiased, p_font_rid, ret)) { +TextServer::FontAntialiasing TextServerExtension::font_get_antialiasing(RID p_font_rid) const { + TextServer::FontAntialiasing ret; + if (GDVIRTUAL_CALL(font_get_antialiasing, p_font_rid, ret)) { return ret; } - return false; + return TextServer::FONT_ANTIALIASING_NONE; } void TextServerExtension::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 81af1b60e56..d6b1c8ac0ad 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -107,10 +107,10 @@ public: GDVIRTUAL2(font_set_style_name, RID, const String &); GDVIRTUAL1RC(String, font_get_style_name, RID); - virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override; - virtual bool font_is_antialiased(const RID &p_font_rid) const override; - GDVIRTUAL2(font_set_antialiased, RID, bool); - GDVIRTUAL1RC(bool, font_is_antialiased, RID); + virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; + virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; + GDVIRTUAL2(font_set_antialiasing, RID, TextServer::FontAntialiasing); + GDVIRTUAL1RC(TextServer::FontAntialiasing, font_get_antialiasing, RID); virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 2bf0837d884..ab5221582de 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -222,8 +222,8 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_style_name", "font_rid", "name"), &TextServer::font_set_style_name); ClassDB::bind_method(D_METHOD("font_get_style_name", "font_rid"), &TextServer::font_get_style_name); - ClassDB::bind_method(D_METHOD("font_set_antialiased", "font_rid", "antialiased"), &TextServer::font_set_antialiased); - ClassDB::bind_method(D_METHOD("font_is_antialiased", "font_rid"), &TextServer::font_is_antialiased); + ClassDB::bind_method(D_METHOD("font_set_antialiasing", "font_rid", "antialiasing"), &TextServer::font_set_antialiasing); + ClassDB::bind_method(D_METHOD("font_get_antialiasing", "font_rid"), &TextServer::font_get_antialiasing); ClassDB::bind_method(D_METHOD("font_set_generate_mipmaps", "font_rid", "generate_mipmaps"), &TextServer::font_set_generate_mipmaps); ClassDB::bind_method(D_METHOD("font_get_generate_mipmaps", "font_rid"), &TextServer::font_get_generate_mipmaps); @@ -457,6 +457,17 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text); + /* Font AA */ + BIND_ENUM_CONSTANT(FONT_ANTIALIASING_NONE); + BIND_ENUM_CONSTANT(FONT_ANTIALIASING_GRAY); + BIND_ENUM_CONSTANT(FONT_ANTIALIASING_LCD); + + BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_NONE); + BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HRGB); + BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HBGR); + BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VRGB); + BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VBGR); + /* Direction */ BIND_ENUM_CONSTANT(DIRECTION_AUTO); BIND_ENUM_CONSTANT(DIRECTION_LTR); diff --git a/servers/text_server.h b/servers/text_server.h index d45bea32719..22d48335d3a 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -44,6 +44,21 @@ class TextServer : public RefCounted { GDCLASS(TextServer, RefCounted); public: + enum FontAntialiasing { + FONT_ANTIALIASING_NONE, + FONT_ANTIALIASING_GRAY, + FONT_ANTIALIASING_LCD, + }; + + enum FontLCDSubpixelLayout { + FONT_LCD_SUBPIXEL_LAYOUT_NONE, + FONT_LCD_SUBPIXEL_LAYOUT_HRGB, + FONT_LCD_SUBPIXEL_LAYOUT_HBGR, + FONT_LCD_SUBPIXEL_LAYOUT_VRGB, + FONT_LCD_SUBPIXEL_LAYOUT_VBGR, + FONT_LCD_SUBPIXEL_LAYOUT_MAX, + }; + enum Direction { DIRECTION_AUTO, DIRECTION_LTR, @@ -230,8 +245,8 @@ public: virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) = 0; virtual String font_get_style_name(const RID &p_font_rid) const = 0; - virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) = 0; - virtual bool font_is_antialiased(const RID &p_font_rid) const = 0; + virtual void font_set_antialiasing(RID p_font_rid, FontAntialiasing p_antialiasing) = 0; + virtual FontAntialiasing font_get_antialiasing(RID p_font_rid) const = 0; virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) = 0; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const = 0; @@ -569,6 +584,8 @@ VARIANT_ENUM_CAST(TextServer::ContourPointTag); VARIANT_ENUM_CAST(TextServer::SpacingType); VARIANT_BITFIELD_CAST(TextServer::FontStyle); VARIANT_ENUM_CAST(TextServer::StructuredTextParser); +VARIANT_ENUM_CAST(TextServer::FontAntialiasing); +VARIANT_ENUM_CAST(TextServer::FontLCDSubpixelLayout); GDVIRTUAL_NATIVE_PTR(Glyph); GDVIRTUAL_NATIVE_PTR(CaretInfo);