From 8b320622f9cf3e79c3f27f88554c02810605ca26 Mon Sep 17 00:00:00 2001 From: Leroy Hopson Date: Wed, 7 Feb 2024 21:37:50 +1300 Subject: [PATCH] Use shader include for fore/background shaders The two shaders use a lot of common logic for co-ordinate and attribute look up, so it makes sense to use a common include shader for both. Adds support for the inverse and blink attributes to the foreground shader. --- addons/godot_xterm/native/src/terminal.cpp | 19 +++-- addons/godot_xterm/native/src/terminal.h | 1 + .../godot_xterm/shaders/background.gdshader | 41 +---------- addons/godot_xterm/shaders/common.gdshaderinc | 73 +++++++++++++++++++ .../godot_xterm/shaders/foreground.gdshader | 10 +-- 5 files changed, 95 insertions(+), 49 deletions(-) create mode 100644 addons/godot_xterm/shaders/common.gdshaderinc diff --git a/addons/godot_xterm/native/src/terminal.cpp b/addons/godot_xterm/native/src/terminal.cpp index b963415..034ce80 100644 --- a/addons/godot_xterm/native/src/terminal.cpp +++ b/addons/godot_xterm/native/src/terminal.cpp @@ -332,14 +332,21 @@ void Terminal::update_sizes(bool force) attr_image = Image::create(std::max(cols, 1u), std::max(rows, 1u), false, Image::FORMAT_L8); attr_texture->set_image(attr_image); - back_material->set_shader_parameter("cols", cols); - back_material->set_shader_parameter("rows", rows); - back_material->set_shader_parameter("size", size); - back_material->set_shader_parameter("cell_size", cell_size); + update_shader_parameters(back_material); + update_shader_parameters(fore_material); refresh(); } +void Terminal::update_shader_parameters(Ref material) +{ + material->set_shader_parameter("cols", cols); + material->set_shader_parameter("rows", rows); + material->set_shader_parameter("size", size); + material->set_shader_parameter("cell_size", cell_size); + material->set_shader_parameter("grid_size", Vector2(cols * cell_size.x, rows * cell_size.y)); +} + void Terminal::initialize_rendering() { ResourceLoader* rl = ResourceLoader::get_singleton(); @@ -354,7 +361,7 @@ void Terminal::initialize_rendering() { back_material.instantiate(); back_material->set_shader(back_shader); - back_material->set_shader_parameter("cell_colors", back_texture); + back_material->set_shader_parameter("background_colors", back_texture); back_material->set_shader_parameter("attributes", attr_texture); back_canvas_item = rs->canvas_item_create(); @@ -404,7 +411,7 @@ void Terminal::update_theme() { tsm_vte_color color = static_cast(i); palette[color] = get_theme_color(String(COLOR_NAMES[i])); } - back_material->set_shader_parameter("background", palette[TSM_COLOR_BACKGROUND]); + back_material->set_shader_parameter("background_color", palette[TSM_COLOR_BACKGROUND]); // TODO: Default to mono font and handle other styles. font = get_theme_font("normal_font"); diff --git a/addons/godot_xterm/native/src/terminal.h b/addons/godot_xterm/native/src/terminal.h index 4a857b4..037902c 100644 --- a/addons/godot_xterm/native/src/terminal.h +++ b/addons/godot_xterm/native/src/terminal.h @@ -97,6 +97,7 @@ namespace godot void initialize_rendering(); void update_theme(); void update_sizes(bool force = false); + void update_shader_parameters(Ref material); void draw_screen(); void refresh(); void cleanup_rendering(); diff --git a/addons/godot_xterm/shaders/background.gdshader b/addons/godot_xterm/shaders/background.gdshader index 97df560..0e843a3 100644 --- a/addons/godot_xterm/shaders/background.gdshader +++ b/addons/godot_xterm/shaders/background.gdshader @@ -1,38 +1,5 @@ +// SPDX-FileCopyrightText: 2024 Leroy Hopson +// SPDX-License-Identifier: MIT shader_type canvas_item; - -uniform int cols; -uniform int rows; -uniform vec2 size; // Total size of the Terminal control. -uniform vec2 cell_size; -uniform vec4 background; -uniform sampler2D cell_colors; // Texture containing the cell colors, one pixel per cell. - -const int INVERSE_FLAG = 1 << 0; -// Texture containing the cell attributes encoded using bit flags, one flag per cell in the R channel. -uniform sampler2D attributes; - -void fragment() { - // Grid means the part of the terminal that contains the cells. - // Will vary depending on font size and the size of the control. - vec2 grid_size = vec2(cell_size.x * float(cols), cell_size.y * float(rows)); - - if (UV.x * size.x < grid_size.x && UV.y * size.y < grid_size.y) { - vec2 grid_uv = UV * size / cell_size; - - int cell_x = int(grid_uv.x); - int cell_y = int(grid_uv.y); - - vec2 sample_uv = (vec2(float(cell_x), float(cell_y)) + 0.5) / vec2(float(cols), float(rows)); - vec4 color = texture(cell_colors, sample_uv); - - int attr_flags = int(texture(attributes, sample_uv).r * 255.0 + 0.5); - if ((attr_flags & INVERSE_FLAG) != 0) { - color = vec4(1.0 - color.rgb, color.a); - } - - COLOR = color; - } else { - // If outside the grid area, use the background color. - COLOR = background; - } -} +#define BACKGROUND +#include "./common.gdshaderinc" \ No newline at end of file diff --git a/addons/godot_xterm/shaders/common.gdshaderinc b/addons/godot_xterm/shaders/common.gdshaderinc new file mode 100644 index 0000000..5c0112d --- /dev/null +++ b/addons/godot_xterm/shaders/common.gdshaderinc @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2024 Leroy Hopson +// SPDX-License-Identifier: MIT + +#define FLAG_INVERSE 1 << 0 +#define FLAG_BLINK 1 << 1 + +#define transparent vec4(0) + +uniform int cols; +uniform int rows; +uniform vec2 size; +uniform vec2 cell_size; +uniform vec2 grid_size; + +uniform sampler2D attributes; + +#ifdef BACKGROUND +uniform vec4 background_color; +uniform sampler2D background_colors; +#endif + +#ifdef FOREGROUND +uniform float blink_off_time = 0.3; +uniform float blink_on_time = 0.6; +#endif + +bool has_attribute(vec2 uv, int flag) { + int flags = int(texture(attributes, uv).r * 255.0 + 0.5); + return (flags & flag) != 0; +} + +void fragment() { + // Check if we are inside the grid. + if (UV.x * size.x < grid_size.x && UV.y * size.y < grid_size.y) { + vec2 grid_uv = UV * size / cell_size; + + int cell_x = int(grid_uv.x); + int cell_y = int(grid_uv.y); + + vec2 sample_uv = (vec2(float(cell_x), float(cell_y)) + 0.5) / vec2(float(cols), float(rows)); + + vec4 color; +#ifdef BACKGROUND + color = texture(background_colors, sample_uv); +#elif defined(FOREGROUND) + color = texture(TEXTURE, UV); +#endif + + if (has_attribute(sample_uv, FLAG_INVERSE)) { + color = vec4(1.0 - color.rgb, color.a); + } + +#ifdef FOREGROUND + if (has_attribute(sample_uv, FLAG_BLINK)) { + float blink_cycle = blink_on_time + blink_off_time; + float current_time = mod(TIME, blink_cycle); + if (current_time > blink_on_time) { + color = transparent; + } + } +#endif + +#if defined(FOREGROUND) || defined(BACKGROUND) + COLOR = color; +#endif + } else { // Outside the grid. +#ifdef BACKGROUND + COLOR = background_color; +#elif defined(FOREGROUND) + COLOR = transparent; +#endif + } +} \ No newline at end of file diff --git a/addons/godot_xterm/shaders/foreground.gdshader b/addons/godot_xterm/shaders/foreground.gdshader index 7812914..afa5793 100644 --- a/addons/godot_xterm/shaders/foreground.gdshader +++ b/addons/godot_xterm/shaders/foreground.gdshader @@ -1,7 +1,5 @@ +// SPDX-FileCopyrightText: 2024 Leroy Hopson +// SPDX-License-Identifier: MIT shader_type canvas_item; - -void fragment() { - COLOR = texture(TEXTURE, UV); - // TODO: Check blink attribute and hide/show using the below. - //COLOR = vec4(0); -} +#define FOREGROUND +#include "./common.gdshaderinc" \ No newline at end of file