mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-19 20:18:07 +00:00
This migrates all remaining uses of cImport (and addTranslateC for good measure) to using translate-c for C translation, ensuring that we are ready for when cImport is removed from the language, and also that all sources of C translation are using the same snapshot of the external package (when can then be updated when we need to fix something). A couple of notes: * A few options have been added to support the new translations, namely the ability to link libraries (passed through to linkLibrary on the Translator side) and whether or not to initialize default values (looks like cImport did this without a way to control it, but translate-c does not do it by default). * Using the new library linking option actually simplifies the process of translating a number of the C packages as we have been shipping the necessary headers for these packages already with the applicable libraries. For some of the more complex translation processes though, we still include the appropriate directories directly.
246 lines
6.9 KiB
Zig
246 lines
6.9 KiB
Zig
const Buffer = @This();
|
|
|
|
const std = @import("std");
|
|
const c = @import("opengl_c");
|
|
const errors = @import("errors.zig");
|
|
const glad = @import("glad.zig");
|
|
|
|
id: c.GLuint,
|
|
|
|
/// Create a single buffer.
|
|
pub fn create() !Buffer {
|
|
var vbo: c.GLuint = undefined;
|
|
glad.context.GenBuffers.?(1, &vbo);
|
|
return Buffer{ .id = vbo };
|
|
}
|
|
|
|
/// glBindBuffer
|
|
pub fn bind(self: Buffer, target: Target) !Binding {
|
|
glad.context.BindBuffer.?(@intFromEnum(target), self.id);
|
|
return Binding{ .id = self.id, .target = target };
|
|
}
|
|
|
|
pub fn destroy(self: Buffer) void {
|
|
glad.context.DeleteBuffers.?(1, &self.id);
|
|
}
|
|
|
|
pub fn bindBase(self: Buffer, target: Target, idx: c.GLuint) !void {
|
|
glad.context.BindBufferBase.?(
|
|
@intFromEnum(target),
|
|
idx,
|
|
self.id,
|
|
);
|
|
try errors.getError();
|
|
}
|
|
|
|
/// Binding is a bound buffer. By using this for functions that operate
|
|
/// on bound buffers, you can easily defer unbinding and in safety-enabled
|
|
/// modes verify that unbound buffers are never accessed.
|
|
pub const Binding = struct {
|
|
id: c.GLuint,
|
|
target: Target,
|
|
|
|
pub fn unbind(b: Binding) void {
|
|
glad.context.BindBuffer.?(@intFromEnum(b.target), 0);
|
|
}
|
|
|
|
/// Sets the data of this bound buffer. The data can be any array-like
|
|
/// type. The size of the data is automatically determined based on the type.
|
|
pub fn setData(
|
|
b: Binding,
|
|
data: anytype,
|
|
usage: Usage,
|
|
) !void {
|
|
const info = dataInfo(data);
|
|
glad.context.BufferData.?(
|
|
@intFromEnum(b.target),
|
|
info.size,
|
|
info.ptr,
|
|
@intFromEnum(usage),
|
|
);
|
|
try errors.getError();
|
|
}
|
|
|
|
/// Sets the data of this bound buffer. The data can be any array-like
|
|
/// type. The size of the data is automatically determined based on the type.
|
|
pub fn setSubData(
|
|
b: Binding,
|
|
offset: usize,
|
|
data: anytype,
|
|
) !void {
|
|
const info = dataInfo(data);
|
|
glad.context.BufferSubData.?(
|
|
@intFromEnum(b.target),
|
|
@intCast(offset),
|
|
info.size,
|
|
info.ptr,
|
|
);
|
|
try errors.getError();
|
|
}
|
|
|
|
/// Sets the buffer data with a null buffer that is expected to be
|
|
/// filled in the future using subData. This requires the type just so
|
|
/// we can setup the data size.
|
|
pub fn setDataNull(
|
|
b: Binding,
|
|
comptime T: type,
|
|
usage: Usage,
|
|
) !void {
|
|
glad.context.BufferData.?(
|
|
@intFromEnum(b.target),
|
|
@sizeOf(T),
|
|
null,
|
|
@intFromEnum(usage),
|
|
);
|
|
try errors.getError();
|
|
}
|
|
|
|
/// Same as setDataNull but lets you manually specify the buffer size.
|
|
pub fn setDataNullManual(
|
|
b: Binding,
|
|
size: usize,
|
|
usage: Usage,
|
|
) !void {
|
|
glad.context.BufferData.?(
|
|
@intFromEnum(b.target),
|
|
@intCast(size),
|
|
null,
|
|
@intFromEnum(usage),
|
|
);
|
|
try errors.getError();
|
|
}
|
|
|
|
fn dataInfo(data: anytype) struct {
|
|
size: isize,
|
|
ptr: *const anyopaque,
|
|
} {
|
|
return switch (@typeInfo(@TypeOf(data))) {
|
|
.pointer => |ptr| switch (ptr.size) {
|
|
.one => .{
|
|
.size = @sizeOf(ptr.child),
|
|
.ptr = data,
|
|
},
|
|
.slice => .{
|
|
.size = @intCast(@sizeOf(ptr.child) * data.len),
|
|
.ptr = data.ptr,
|
|
},
|
|
else => {
|
|
std.log.err("invalid buffer data pointer size: {}", .{ptr.size});
|
|
unreachable;
|
|
},
|
|
},
|
|
else => {
|
|
std.log.err("invalid buffer data type: {s}", .{@tagName(@typeInfo(@TypeOf(data)))});
|
|
unreachable;
|
|
},
|
|
};
|
|
}
|
|
|
|
/// Shorthand for vertexAttribPointer that is specialized towards the
|
|
/// common use case of specifying an array of homogeneous types that
|
|
/// don't need normalization. This also enables the attribute at idx.
|
|
pub fn attribute(
|
|
b: Binding,
|
|
idx: c.GLuint,
|
|
size: c.GLint,
|
|
comptime T: type,
|
|
offset: usize,
|
|
) !void {
|
|
const info: struct {
|
|
// Type of the each component in the array.
|
|
typ: c.GLenum,
|
|
|
|
// The byte offset between each full set of attributes.
|
|
stride: c.GLsizei,
|
|
|
|
// The size of each component used in calculating the offset.
|
|
offset: usize,
|
|
} = switch (@typeInfo(T)) {
|
|
.Array => |ary| .{
|
|
.typ = switch (ary.child) {
|
|
f32 => c.GL_FLOAT,
|
|
else => @compileError("unsupported array child type"),
|
|
},
|
|
.offset = @sizeOf(ary.child),
|
|
.stride = @sizeOf(T),
|
|
},
|
|
else => @compileError("unsupported type"),
|
|
};
|
|
|
|
try b.attributeAdvanced(
|
|
idx,
|
|
size,
|
|
info.typ,
|
|
false,
|
|
info.stride,
|
|
offset * info.offset,
|
|
);
|
|
try b.enableAttribArray(idx);
|
|
}
|
|
|
|
/// VertexAttribDivisor
|
|
pub fn attributeDivisor(_: Binding, idx: c.GLuint, divisor: c.GLuint) !void {
|
|
glad.context.VertexAttribDivisor.?(idx, divisor);
|
|
try errors.getError();
|
|
}
|
|
|
|
pub fn attributeAdvanced(
|
|
_: Binding,
|
|
idx: c.GLuint,
|
|
size: c.GLint,
|
|
typ: c.GLenum,
|
|
normalized: bool,
|
|
stride: c.GLsizei,
|
|
offset: usize,
|
|
) !void {
|
|
const normalized_c: c.GLboolean = if (normalized) c.GL_TRUE else c.GL_FALSE;
|
|
const offsetPtr = if (offset > 0)
|
|
@as(*const anyopaque, @ptrFromInt(offset))
|
|
else
|
|
null;
|
|
|
|
glad.context.VertexAttribPointer.?(idx, size, typ, normalized_c, stride, offsetPtr);
|
|
try errors.getError();
|
|
}
|
|
|
|
pub fn attributeIAdvanced(
|
|
_: Binding,
|
|
idx: c.GLuint,
|
|
size: c.GLint,
|
|
typ: c.GLenum,
|
|
stride: c.GLsizei,
|
|
offset: usize,
|
|
) !void {
|
|
const offsetPtr = if (offset > 0)
|
|
@as(*const anyopaque, @ptrFromInt(offset))
|
|
else
|
|
null;
|
|
|
|
glad.context.VertexAttribIPointer.?(idx, size, typ, stride, offsetPtr);
|
|
try errors.getError();
|
|
}
|
|
};
|
|
|
|
/// Enum for possible binding targets.
|
|
pub const Target = enum(c_uint) {
|
|
array = c.GL_ARRAY_BUFFER,
|
|
element_array = c.GL_ELEMENT_ARRAY_BUFFER,
|
|
uniform = c.GL_UNIFORM_BUFFER,
|
|
storage = c.GL_SHADER_STORAGE_BUFFER,
|
|
_,
|
|
};
|
|
|
|
/// Enum for possible buffer usages.
|
|
pub const Usage = enum(c_uint) {
|
|
stream_draw = c.GL_STREAM_DRAW,
|
|
stream_read = c.GL_STREAM_READ,
|
|
stream_copy = c.GL_STREAM_COPY,
|
|
static_draw = c.GL_STATIC_DRAW,
|
|
static_read = c.GL_STATIC_READ,
|
|
static_copy = c.GL_STATIC_COPY,
|
|
dynamic_draw = c.GL_DYNAMIC_DRAW,
|
|
dynamic_read = c.GL_DYNAMIC_READ,
|
|
dynamic_copy = c.GL_DYNAMIC_COPY,
|
|
_,
|
|
};
|