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 WindowPaddingColor = Config.WindowPaddingColor;
pub const BackgroundImageMode = Config.BackgroundImageMode;
pub const BackgroundImagePosition = Config.BackgroundImagePosition;
// Alternate APIs
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
/// but cropping the image to fill the window, as needed.
/// * `tiled` - Image is repeated horizontally and vertically to fill the window.
/// * `centered` - Image is centered in the window and displayed 1-to-1 pixel
/// scale, preserving both the aspect 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.
/// * `none` - Image is displayed 1-to-1 pixel scale, preserving both the aspect
/// ratio and the image size.
///
@"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 selection color is just the inverted window background and foreground
@ -6197,10 +6204,24 @@ pub const BackgroundImageMode = enum(u8) {
fill = 1,
cover = 2,
tiled = 3,
centered = 4,
@"top-left" = 5,
@"top-right" = 6,
@"bottom-left" = 7,
none = 4,
};
/// 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,
};

View File

@ -149,6 +149,9 @@ background_image_opacity: f32,
/// The background image mode to use.
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
/// draw any background image.
current_background_image: ?Image = null,
@ -302,6 +305,7 @@ pub const DerivedConfig = struct {
background_image: ?configpkg.Path,
background_image_opacity: f32,
background_image_mode: configpkg.BackgroundImageMode,
background_image_position: configpkg.BackgroundImagePosition,
foreground: terminal.color.RGB,
selection_background: ?terminal.color.RGB,
selection_foreground: ?terminal.color.RGB,
@ -370,6 +374,7 @@ pub const DerivedConfig = struct {
.background_image = background_image,
.background_image_opacity = config.@"background-image-opacity",
.background_image_mode = config.@"background-image-mode",
.background_image_position = config.@"background-image-position",
.invert_selection_fg_bg = config.@"selection-invert-fg-bg",
.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_opacity = options.config.background_image_opacity,
.background_image_mode = options.config.background_image_mode,
.background_image_position = options.config.background_image_position,
.cursor_invert = options.config.cursor_invert,
.surface_mailbox = options.surface_mailbox,
.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_opacity = config.background_image_opacity;
self.background_image_mode = config.background_image_mode;
self.background_image_position = config.background_image_position;
if (self.current_background_image) |*img| {
img.markForUnload();
}
@ -2635,6 +2642,7 @@ fn drawBackgroundImage(
.terminal_width = self.size.terminal().width,
.terminal_height = self.size.terminal().height,
.mode = self.background_image_mode,
.position_index = self.background_image_position,
}, .static_draw);
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
mode: configpkg.BackgroundImageMode = .contain,
/// uint position_index
position_index: configpkg.BackgroundImagePosition = .center,
};
program: gl.Program,
@ -60,10 +63,14 @@ pub fn init() !BackgroundImageProgram {
offset += 2 * @sizeOf(u32);
try vbobind.attributeIAdvanced(1, 1, gl.c.GL_UNSIGNED_BYTE, @sizeOf(Input), offset);
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(1);
try vbobind.enableAttribArray(2);
try vbobind.attributeDivisor(0, 1);
try vbobind.attributeDivisor(1, 1);
try vbobind.attributeDivisor(2, 1);
return .{
.program = program,

View File

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