Add support for customizing background image offset

This commit is contained in:
yunusey
2025-05-24 15:46:43 -04:00
parent 50cf2fee6a
commit 624a8c812c
5 changed files with 60 additions and 47 deletions

View File

@ -34,6 +34,7 @@ pub const Path = Config.Path;
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures; pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
pub const WindowPaddingColor = Config.WindowPaddingColor; pub const WindowPaddingColor = Config.WindowPaddingColor;
pub const BackgroundImageMode = Config.BackgroundImageMode; pub const BackgroundImageMode = Config.BackgroundImageMode;
pub const BackgroundImagePosition = Config.BackgroundImagePosition;
// Alternate APIs // Alternate APIs
pub const CAPI = @import("config/CAPI.zig"); pub const CAPI = @import("config/CAPI.zig");

View File

@ -474,18 +474,25 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// * `cover` - Image is centered in the window, preserving the aspect ratio /// * `cover` - Image is centered in the window, preserving the aspect ratio
/// but cropping the image to fill the window, as needed. /// but cropping the image to fill the window, as needed.
/// * `tiled` - Image is repeated horizontally and vertically to fill the window. /// * `tiled` - Image is repeated horizontally and vertically to fill the window.
/// * `centered` - Image is centered in the window and displayed 1-to-1 pixel /// * `none` - Image is displayed 1-to-1 pixel scale, preserving both the aspect
/// scale, preserving both the aspect ratio and the image size. /// ratio and the image size.
/// * `top-left` - Image is anchored to the top left corner of the window,
/// preserving the aspect ratio.
/// * `top-right` - Image is anchored to the top right corner of the window,
/// preserving the aspect ratio.
/// * `bottom-left` - Image is anchored to the bottom left corner of the window,
/// preserving the aspect ratio.
/// * `bottom-right` - Image is anchored to the bottom right corner of the window,
/// preserving the aspect ratio.
/// ///
@"background-image-mode": BackgroundImageMode = .contain, @"background-image-mode": BackgroundImageMode = .none,
/// Background image position.
///
/// Valid values are:
/// * `top-left`
/// * `top-center`
/// * `top-right`
/// * `center-left`
/// * `center`
/// * `center-right`
/// * `bottom-left`
/// * `bottom-center`
/// * `bottom-right`
///
@"background-image-position": BackgroundImagePosition = .center,
/// The foreground and background color for selection. If this is not set, then /// The foreground and background color for selection. If this is not set, then
/// the selection color is just the inverted window background and foreground /// the selection color is just the inverted window background and foreground
@ -6197,10 +6204,24 @@ pub const BackgroundImageMode = enum(u8) {
fill = 1, fill = 1,
cover = 2, cover = 2,
tiled = 3, tiled = 3,
centered = 4, none = 4,
@"top-left" = 5, };
@"top-right" = 6,
@"bottom-left" = 7, /// See background-image-position
///
/// This enum is used to set the background image position. The shader expects
/// a `uint`, so we use `u8` here. The values for each position should be kept
/// in sync with the values in the vertex shader used to render the
/// background image (`bgimage`).
pub const BackgroundImagePosition = enum(u8) {
@"top-left" = 0,
@"top-center" = 1,
@"top-right" = 2,
@"center-left" = 3,
center = 4,
@"center-right" = 5,
@"bottom-left" = 6,
@"bottom-center" = 7,
@"bottom-right" = 8, @"bottom-right" = 8,
}; };

View File

@ -149,6 +149,9 @@ background_image_opacity: f32,
/// The background image mode to use. /// The background image mode to use.
background_image_mode: configpkg.BackgroundImageMode, background_image_mode: configpkg.BackgroundImageMode,
/// The background image position to use.
background_image_position: configpkg.BackgroundImagePosition,
/// The current background image to draw. If it is null, then we will not /// The current background image to draw. If it is null, then we will not
/// draw any background image. /// draw any background image.
current_background_image: ?Image = null, current_background_image: ?Image = null,
@ -302,6 +305,7 @@ pub const DerivedConfig = struct {
background_image: ?configpkg.Path, background_image: ?configpkg.Path,
background_image_opacity: f32, background_image_opacity: f32,
background_image_mode: configpkg.BackgroundImageMode, background_image_mode: configpkg.BackgroundImageMode,
background_image_position: configpkg.BackgroundImagePosition,
foreground: terminal.color.RGB, foreground: terminal.color.RGB,
selection_background: ?terminal.color.RGB, selection_background: ?terminal.color.RGB,
selection_foreground: ?terminal.color.RGB, selection_foreground: ?terminal.color.RGB,
@ -370,6 +374,7 @@ pub const DerivedConfig = struct {
.background_image = background_image, .background_image = background_image,
.background_image_opacity = config.@"background-image-opacity", .background_image_opacity = config.@"background-image-opacity",
.background_image_mode = config.@"background-image-mode", .background_image_mode = config.@"background-image-mode",
.background_image_position = config.@"background-image-position",
.invert_selection_fg_bg = config.@"selection-invert-fg-bg", .invert_selection_fg_bg = config.@"selection-invert-fg-bg",
.bold_is_bright = config.@"bold-is-bright", .bold_is_bright = config.@"bold-is-bright",
@ -438,6 +443,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
.background_image = options.config.background_image, .background_image = options.config.background_image,
.background_image_opacity = options.config.background_image_opacity, .background_image_opacity = options.config.background_image_opacity,
.background_image_mode = options.config.background_image_mode, .background_image_mode = options.config.background_image_mode,
.background_image_position = options.config.background_image_position,
.cursor_invert = options.config.cursor_invert, .cursor_invert = options.config.cursor_invert,
.surface_mailbox = options.surface_mailbox, .surface_mailbox = options.surface_mailbox,
.deferred_font_size = .{ .metrics = grid.metrics }, .deferred_font_size = .{ .metrics = grid.metrics },
@ -2288,6 +2294,7 @@ pub fn changeConfig(self: *OpenGL, config: *DerivedConfig) !void {
self.background_image = config.background_image; self.background_image = config.background_image;
self.background_image_opacity = config.background_image_opacity; self.background_image_opacity = config.background_image_opacity;
self.background_image_mode = config.background_image_mode; self.background_image_mode = config.background_image_mode;
self.background_image_position = config.background_image_position;
if (self.current_background_image) |*img| { if (self.current_background_image) |*img| {
img.markForUnload(); img.markForUnload();
} }
@ -2635,6 +2642,7 @@ fn drawBackgroundImage(
.terminal_width = self.size.terminal().width, .terminal_width = self.size.terminal().width,
.terminal_height = self.size.terminal().height, .terminal_height = self.size.terminal().height,
.mode = self.background_image_mode, .mode = self.background_image_mode,
.position_index = self.background_image_position,
}, .static_draw); }, .static_draw);
try gl_state.bgimage_program.program.setUniform("opacity", self.config.background_image_opacity); try gl_state.bgimage_program.program.setUniform("opacity", self.config.background_image_opacity);

View File

@ -12,6 +12,9 @@ pub const Input = extern struct {
/// uint mode /// uint mode
mode: configpkg.BackgroundImageMode = .contain, mode: configpkg.BackgroundImageMode = .contain,
/// uint position_index
position_index: configpkg.BackgroundImagePosition = .center,
}; };
program: gl.Program, program: gl.Program,
@ -60,10 +63,14 @@ pub fn init() !BackgroundImageProgram {
offset += 2 * @sizeOf(u32); offset += 2 * @sizeOf(u32);
try vbobind.attributeIAdvanced(1, 1, gl.c.GL_UNSIGNED_BYTE, @sizeOf(Input), offset); try vbobind.attributeIAdvanced(1, 1, gl.c.GL_UNSIGNED_BYTE, @sizeOf(Input), offset);
offset += 1 * @sizeOf(u8); offset += 1 * @sizeOf(u8);
try vbobind.attributeIAdvanced(2, 1, gl.c.GL_UNSIGNED_BYTE, @sizeOf(Input), offset);
offset += 1 * @sizeOf(u8);
try vbobind.enableAttribArray(0); try vbobind.enableAttribArray(0);
try vbobind.enableAttribArray(1); try vbobind.enableAttribArray(1);
try vbobind.enableAttribArray(2);
try vbobind.attributeDivisor(0, 1); try vbobind.attributeDivisor(0, 1);
try vbobind.attributeDivisor(1, 1); try vbobind.attributeDivisor(1, 1);
try vbobind.attributeDivisor(2, 1);
return .{ return .{
.program = program, .program = program,

View File

@ -7,14 +7,11 @@ const uint MODE_CONTAIN = 0u;
const uint MODE_FILL = 1u; const uint MODE_FILL = 1u;
const uint MODE_COVER = 2u; const uint MODE_COVER = 2u;
const uint MODE_TILED = 3u; const uint MODE_TILED = 3u;
const uint MODE_CENTERED = 4u; const uint MODE_NONE = 4u;
const uint MODE_TOP_LEFT = 5u;
const uint MODE_TOP_RIGHT = 6u;
const uint MODE_BOTTOM_LEFT = 7u;
const uint MODE_BOTTOM_RIGHT = 8u;
layout (location = 0) in vec2 terminal_size; layout (location = 0) in vec2 terminal_size;
layout (location = 1) in uint mode; layout (location = 1) in uint mode;
layout (location = 2) in uint position_index;
out vec2 tex_coord; out vec2 tex_coord;
@ -58,12 +55,8 @@ void main() {
scale.y = aspect_ratio.x / aspect_ratio.y; scale.y = aspect_ratio.x / aspect_ratio.y;
} }
break; break;
case MODE_CENTERED: case MODE_NONE:
case MODE_TOP_LEFT: // If none, the final scale of the image should match the actual
case MODE_TOP_RIGHT:
case MODE_BOTTOM_LEFT:
case MODE_BOTTOM_RIGHT:
// If centered, the final scale of the image should match the actual
// size of the image and should be centered // size of the image and should be centered
scale.x = image_size.x / terminal_size.x; scale.x = image_size.x / terminal_size.x;
scale.y = image_size.y / terminal_size.y; scale.y = image_size.y / terminal_size.y;
@ -76,27 +69,10 @@ void main() {
vec2 final_image_size = terminal_size * position * scale; vec2 final_image_size = terminal_size * position * scale;
vec2 offset = vec2(0.0, 0.0); vec2 offset = vec2(0.0, 0.0);
switch (mode) {
case MODE_CONTAIN: uint y_pos = position_index / 3u; // 0 = top, 1 = center, 2 = bottom
case MODE_FILL: uint x_pos = position_index % 3u; // 0 = left, 1 = center, 2 = right
case MODE_COVER: offset = ((terminal_size * (1.0 - scale)) / 2.0) * vec2(x_pos, y_pos);
case MODE_TILED:
case MODE_CENTERED:
offset = (terminal_size * (1.0 - scale)) / 2.0;
break;
case MODE_TOP_LEFT:
offset = vec2(0.0, 0.0);
break;
case MODE_TOP_RIGHT:
offset = vec2(terminal_size.x - image_size.x, 0.0);
break;
case MODE_BOTTOM_LEFT:
offset = vec2(0.0, terminal_size.y - image_size.y);
break;
case MODE_BOTTOM_RIGHT:
offset = vec2(terminal_size.x - image_size.x, terminal_size.y - image_size.y);
break;
}
gl_Position = projection * vec4(final_image_size.xy + offset, 0.0, 1.0); gl_Position = projection * vec4(final_image_size.xy + offset, 0.0, 1.0);
tex_coord = position; tex_coord = position;
if (mode == MODE_TILED) { if (mode == MODE_TILED) {