ghostty/src/renderer/opengl/Texture.zig
2025-06-20 15:18:41 -06:00

99 lines
2.2 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,
};
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,
/// Initialize a texture
pub fn init(
opts: Options,
width: usize,
height: usize,
data: ?[]const u8,
) !Self {
const tex = try gl.Texture.create();
errdefer tex.destroy();
{
const texbind = try tex.bind(opts.target);
defer texbind.unbind();
try texbind.parameter(.WrapS, gl.c.GL_CLAMP_TO_EDGE);
try texbind.parameter(.WrapT, gl.c.GL_CLAMP_TO_EDGE);
try texbind.parameter(.MinFilter, gl.c.GL_LINEAR);
try texbind.parameter(.MagFilter, gl.c.GL_LINEAR);
try texbind.image2D(
0,
opts.internal_format,
@intCast(width),
@intCast(height),
0,
opts.format,
.UnsignedByte,
if (data) |d| @ptrCast(d.ptr) else null,
);
}
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,
) !void {
const texbind = try self.texture.bind(self.target);
defer texbind.unbind();
try texbind.subImage2D(
0,
@intCast(x),
@intCast(y),
@intCast(width),
@intCast(height),
self.format,
.UnsignedByte,
data.ptr,
);
}