From a5a2196d527ff348397d543c1753de16599616bf Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 1 Apr 2022 18:00:15 -0700 Subject: [PATCH] opengl: bound buffers --- src/main.zig | 6 +-- src/opengl/Buffer.zig | 106 +++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/main.zig b/src/main.zig index a882463d6..21ed0cba3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -55,8 +55,8 @@ pub fn main() !void { const vbo = try gl.Buffer.create(); defer vbo.destroy(); try vao.bind(); - try vbo.bind(c.GL_ARRAY_BUFFER); - try vbo.setData(c.GL_ARRAY_BUFFER, vertices, c.GL_STATIC_DRAW); + var binding = try vbo.bind(c.GL_ARRAY_BUFFER); + try binding.setData(&vertices, c.GL_STATIC_DRAW); c.glVertexAttribPointer( 0, @@ -68,7 +68,7 @@ pub fn main() !void { ); c.glEnableVertexAttribArray(0); - try gl.Buffer.unbind(c.GL_ARRAY_BUFFER); + binding.unbind(); try gl.VertexArray.unbind(); // Wait for the user to close the window. diff --git a/src/opengl/Buffer.zig b/src/opengl/Buffer.zig index e5d47133c..c980669af 100644 --- a/src/opengl/Buffer.zig +++ b/src/opengl/Buffer.zig @@ -6,6 +6,61 @@ const errors = @import("errors.zig"); id: c.GLuint, +/// 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 { + target: c.GLenum, + + /// 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 inline fn setData( + b: Binding, + data: anytype, + usage: c.GLenum, + ) !void { + // Determine the size and pointer to the given data. + const info: struct { + size: isize, + ptr: *const anyopaque, + } = switch (@typeInfo(@TypeOf(data))) { + .Array => |ary| .{ + .size = @sizeOf(ary.child) * ary.len, + .ptr = &data, + }, + .Pointer => |ptr| switch (ptr.size) { + .One => .{ + .size = @sizeOf(ptr.child) * data.len, + .ptr = data, + }, + .Slice => .{ + .size = @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; + }, + }; + + c.glBufferData(b.target, info.size, info.ptr, usage); + try errors.getError(); + } + + pub inline fn unbind(b: *Binding) void { + c.glBindBuffer(b.target, 0); + + // By setting this to undefined, this ensures that any future calls + // error in safe build modes. + b.* = undefined; + } +}; + /// Create a single buffer. pub inline fn create() !Buffer { var vbo: c.GLuint = undefined; @@ -13,57 +68,10 @@ pub inline fn create() !Buffer { return Buffer{ .id = vbo }; } -// Unbind any active vertex array. -pub inline fn unbind(target: c.GLenum) !void { - c.glBindBuffer(target, 0); -} - /// glBindBuffer -pub inline fn bind(v: Buffer, target: c.GLenum) !void { +pub inline fn bind(v: Buffer, target: c.GLenum) !Binding { c.glBindBuffer(target, v.id); -} - -pub inline fn setData( - v: Buffer, - target: c.GLenum, - data: anytype, - usage: c.GLenum, -) !void { - // Maybe one day in debug mode we can validate that this buffer - // is currently bound. - _ = v; - - // Determine the size and pointer to the given data. - const info: struct { - size: isize, - ptr: *const anyopaque, - } = switch (@typeInfo(@TypeOf(data))) { - .Array => |ary| .{ - .size = @sizeOf(ary.child) * ary.len, - .ptr = &data, - }, - .Pointer => |ptr| switch (ptr.size) { - .One => .{ - .size = @sizeOf(ptr.child) * data.len, - .ptr = data, - }, - .Slice => .{ - .size = @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; - }, - }; - - c.glBufferData(target, info.size, info.ptr, usage); - try errors.getError(); + return Binding{ .target = target }; } pub inline fn destroy(v: Buffer) void {