mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00

This sets up for a couple improvments (see TODO comments) and also sets the glyph atlas textures to nearest neighbor sampling since we can do that now that we never scale glyphs.
107 lines
2.7 KiB
Zig
107 lines
2.7 KiB
Zig
//! Wrapper for handling textures.
|
|
const Self = @This();
|
|
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const assert = std.debug.assert;
|
|
const builtin = @import("builtin");
|
|
const gl = @import("opengl");
|
|
|
|
const OpenGL = @import("../OpenGL.zig");
|
|
|
|
const log = std.log.scoped(.opengl);
|
|
|
|
/// Options for initializing a texture.
|
|
pub const Options = struct {
|
|
format: gl.Texture.Format,
|
|
internal_format: gl.Texture.InternalFormat,
|
|
target: gl.Texture.Target,
|
|
min_filter: gl.Texture.MinFilter,
|
|
mag_filter: gl.Texture.MagFilter,
|
|
wrap_s: gl.Texture.Wrap,
|
|
wrap_t: gl.Texture.Wrap,
|
|
};
|
|
|
|
texture: gl.Texture,
|
|
|
|
/// The width of this texture.
|
|
width: usize,
|
|
/// The height of this texture.
|
|
height: usize,
|
|
|
|
/// Format for this texture.
|
|
format: gl.Texture.Format,
|
|
|
|
/// Target for this texture.
|
|
target: gl.Texture.Target,
|
|
|
|
pub const Error = error{
|
|
/// An OpenGL API call failed.
|
|
OpenGLFailed,
|
|
};
|
|
|
|
/// Initialize a texture
|
|
pub fn init(
|
|
opts: Options,
|
|
width: usize,
|
|
height: usize,
|
|
data: ?[]const u8,
|
|
) Error!Self {
|
|
const tex = gl.Texture.create() catch return error.OpenGLFailed;
|
|
errdefer tex.destroy();
|
|
{
|
|
const texbind = tex.bind(opts.target) catch return error.OpenGLFailed;
|
|
defer texbind.unbind();
|
|
texbind.parameter(.WrapS, @intFromEnum(opts.wrap_s)) catch return error.OpenGLFailed;
|
|
texbind.parameter(.WrapT, @intFromEnum(opts.wrap_t)) catch return error.OpenGLFailed;
|
|
texbind.parameter(.MinFilter, @intFromEnum(opts.min_filter)) catch return error.OpenGLFailed;
|
|
texbind.parameter(.MagFilter, @intFromEnum(opts.mag_filter)) catch return error.OpenGLFailed;
|
|
texbind.image2D(
|
|
0,
|
|
opts.internal_format,
|
|
@intCast(width),
|
|
@intCast(height),
|
|
opts.format,
|
|
.UnsignedByte,
|
|
if (data) |d| @ptrCast(d.ptr) else null,
|
|
) catch return error.OpenGLFailed;
|
|
}
|
|
|
|
return .{
|
|
.texture = tex,
|
|
.width = width,
|
|
.height = height,
|
|
.format = opts.format,
|
|
.target = opts.target,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: Self) void {
|
|
self.texture.destroy();
|
|
}
|
|
|
|
/// Replace a region of the texture with the provided data.
|
|
///
|
|
/// Does NOT check the dimensions of the data to ensure correctness.
|
|
pub fn replaceRegion(
|
|
self: Self,
|
|
x: usize,
|
|
y: usize,
|
|
width: usize,
|
|
height: usize,
|
|
data: []const u8,
|
|
) Error!void {
|
|
const texbind = self.texture.bind(self.target) catch return error.OpenGLFailed;
|
|
defer texbind.unbind();
|
|
texbind.subImage2D(
|
|
0,
|
|
@intCast(x),
|
|
@intCast(y),
|
|
@intCast(width),
|
|
@intCast(height),
|
|
self.format,
|
|
.UnsignedByte,
|
|
data.ptr,
|
|
) catch return error.OpenGLFailed;
|
|
}
|