diff --git a/pkg/opengl/Sampler.zig b/pkg/opengl/Sampler.zig index 82c4c1505..c4fad658f 100644 --- a/pkg/opengl/Sampler.zig +++ b/pkg/opengl/Sampler.zig @@ -24,8 +24,8 @@ pub fn bind(v: Sampler, index: c_uint) !void { pub fn parameter( self: Sampler, - name: Texture.Parameter, - value: anytype, + comptime name: Texture.Parameter, + value: name.Type(), ) errors.Error!void { switch (@TypeOf(value)) { c.GLint => glad.context.SamplerParameteri.?( diff --git a/pkg/opengl/Texture.zig b/pkg/opengl/Texture.zig index fea6ce3e6..06a454df6 100644 --- a/pkg/opengl/Texture.zig +++ b/pkg/opengl/Texture.zig @@ -33,36 +33,45 @@ pub fn destroy(v: Texture) void { /// Enum for possible texture binding targets. pub const Target = enum(c_uint) { - @"1D" = c.GL_TEXTURE_1D, - @"2D" = c.GL_TEXTURE_2D, - @"3D" = c.GL_TEXTURE_3D, - @"1DArray" = c.GL_TEXTURE_1D_ARRAY, - @"2DArray" = c.GL_TEXTURE_2D_ARRAY, - Rectangle = c.GL_TEXTURE_RECTANGLE, - CubeMap = c.GL_TEXTURE_CUBE_MAP, - Buffer = c.GL_TEXTURE_BUFFER, - @"2DMultisample" = c.GL_TEXTURE_2D_MULTISAMPLE, - @"2DMultisampleArray" = c.GL_TEXTURE_2D_MULTISAMPLE_ARRAY, + @"1d" = c.GL_TEXTURE_1D, + @"2d" = c.GL_TEXTURE_2D, + @"3d" = c.GL_TEXTURE_3D, + @"1d_array" = c.GL_TEXTURE_1D_ARRAY, + @"2d_array" = c.GL_TEXTURE_2D_ARRAY, + rectangle = c.GL_TEXTURE_RECTANGLE, + cube_map = c.GL_TEXTURE_CUBE_MAP, + buffer = c.GL_TEXTURE_BUFFER, + @"2d_multisample" = c.GL_TEXTURE_2D_MULTISAMPLE, + @"2d_multisample_array" = c.GL_TEXTURE_2D_MULTISAMPLE_ARRAY, }; /// Enum for possible texture parameters. pub const Parameter = enum(c_uint) { - BaseLevel = c.GL_TEXTURE_BASE_LEVEL, - CompareFunc = c.GL_TEXTURE_COMPARE_FUNC, - CompareMode = c.GL_TEXTURE_COMPARE_MODE, - LodBias = c.GL_TEXTURE_LOD_BIAS, - MinFilter = c.GL_TEXTURE_MIN_FILTER, - MagFilter = c.GL_TEXTURE_MAG_FILTER, - MinLod = c.GL_TEXTURE_MIN_LOD, - MaxLod = c.GL_TEXTURE_MAX_LOD, - MaxLevel = c.GL_TEXTURE_MAX_LEVEL, - SwizzleR = c.GL_TEXTURE_SWIZZLE_R, - SwizzleG = c.GL_TEXTURE_SWIZZLE_G, - SwizzleB = c.GL_TEXTURE_SWIZZLE_B, - SwizzleA = c.GL_TEXTURE_SWIZZLE_A, - WrapS = c.GL_TEXTURE_WRAP_S, - WrapT = c.GL_TEXTURE_WRAP_T, - WrapR = c.GL_TEXTURE_WRAP_R, + base_level = c.GL_TEXTURE_BASE_LEVEL, + compare_func = c.GL_TEXTURE_COMPARE_FUNC, + compare_mode = c.GL_TEXTURE_COMPARE_MODE, + lod_bias = c.GL_TEXTURE_LOD_BIAS, + min_filter = c.GL_TEXTURE_MIN_FILTER, + mag_filter = c.GL_TEXTURE_MAG_FILTER, + min_lod = c.GL_TEXTURE_MIN_LOD, + max_lod = c.GL_TEXTURE_MAX_LOD, + max_level = c.GL_TEXTURE_MAX_LEVEL, + swizzle_r = c.GL_TEXTURE_SWIZZLE_R, + swizzle_g = c.GL_TEXTURE_SWIZZLE_G, + swizzle_b = c.GL_TEXTURE_SWIZZLE_B, + swizzle_a = c.GL_TEXTURE_SWIZZLE_A, + wrap_s = c.GL_TEXTURE_WRAP_S, + wrap_t = c.GL_TEXTURE_WRAP_T, + wrap_r = c.GL_TEXTURE_WRAP_R, + + pub fn Type(comptime self: Parameter) type { + return switch (self) { + .min_filter => MinFilter, + .mag_filter => MagFilter, + .wrap_s, .wrap_t, .wrap_r => Wrap, + else => c.GLint, + }; + } }; /// Internal format enum for texture images. @@ -118,7 +127,7 @@ pub const Wrap = enum(c_int) { /// Data type for texture images. pub const DataType = enum(c_uint) { - UnsignedByte = c.GL_UNSIGNED_BYTE, + unsigned_byte = c.GL_UNSIGNED_BYTE, // There are so many more that I haven't filled in. _, @@ -135,14 +144,21 @@ pub const Binding = struct { glad.context.GenerateMipmap.?(@intFromEnum(b.target)); } - pub fn parameter(b: Binding, name: Parameter, value: anytype) errors.Error!void { - switch (@TypeOf(value)) { + pub fn parameter(b: Binding, comptime name: Parameter, value: name.Type()) errors.Error!void { + switch (name.Type()) { c.GLint => glad.context.TexParameteri.?( @intFromEnum(b.target), @intFromEnum(name), value, ), - else => unreachable, + else => switch (@typeInfo(name.Type())) { + .@"enum" => glad.context.TexParameteri.?( + @intFromEnum(b.target), + @intFromEnum(name), + @intFromEnum(value), + ), + else => @compileError("unknown parameter type"), + }, } try errors.getError(); } diff --git a/pkg/opengl/draw.zig b/pkg/opengl/draw.zig index 8c205864a..e932baca4 100644 --- a/pkg/opengl/draw.zig +++ b/pkg/opengl/draw.zig @@ -1,7 +1,9 @@ +const std = @import("std"); const c = @import("c"); const errors = @import("errors.zig"); const glad = @import("glad.zig"); const Primitive = @import("primitives.zig").Primitive; +const Texture = @import("Texture.zig"); pub fn clearColor(r: f32, g: f32, b: f32, a: f32) void { glad.context.ClearColor.?(r, g, b, a); @@ -75,11 +77,60 @@ pub fn blendFunc(sfactor: c.GLenum, dfactor: c.GLenum) !void { pub fn viewport(x: c.GLint, y: c.GLint, width: c.GLsizei, height: c.GLsizei) !void { glad.context.Viewport.?(x, y, width, height); + try errors.getError(); +} + +pub fn readPixels( + x: c.GLint, + y: c.GLint, + width: c.GLsizei, + height: c.GLsizei, + format: Texture.Format, + typ: Texture.DataType, + data: ?*anyopaque, +) !void { + glad.context.ReadPixels.?( + x, + y, + width, + height, + @intFromEnum(format), + @intFromEnum(typ), + data, + ); + try errors.getError(); +} + +pub fn blitFramebuffer( + src_x0: c.GLint, + src_y0: c.GLint, + src_x1: c.GLint, + src_y1: c.GLint, + dst_x0: c.GLint, + dst_y0: c.GLint, + dst_x1: c.GLint, + dst_y1: c.GLint, + mask: BlitMask, + filter: Texture.MagFilter, +) !void { + glad.context.BlitFramebuffer.?( + src_x0, + src_y0, + src_x1, + src_y1, + dst_x0, + dst_y0, + dst_x1, + dst_y1, + @bitCast(mask), + @intCast(@intFromEnum(filter)), + ); + try errors.getError(); } pub fn pixelStore(mode: c.GLenum, value: anytype) !void { switch (@typeInfo(@TypeOf(value))) { - .ComptimeInt, .Int => glad.context.PixelStorei.?(mode, value), + .comptime_int, .int => glad.context.PixelStorei.?(mode, value), else => unreachable, } try errors.getError(); @@ -92,3 +143,13 @@ pub fn finish() void { pub fn flush() void { glad.context.Flush.?(); } + +pub const BlitMask = packed struct(c.GLbitfield) { + _pad1: u8 = 0, + depth_buffer_bit: bool = false, + _pad2: u1 = 0, + stencil_buffer_bit: bool = false, + _pad3: u3 = 0, + color_buffer_bit: bool = false, + _pad4: std.meta.Int(.unsigned, @bitSizeOf(c.GLbitfield) - 15) = 0, +}; diff --git a/pkg/opengl/main.zig b/pkg/opengl/main.zig index c3f17a7ce..c99909eb2 100644 --- a/pkg/opengl/main.zig +++ b/pkg/opengl/main.zig @@ -42,5 +42,6 @@ pub const frontFace = draw.frontFace; pub const readPixels = draw.readPixels; pub const pixelStore = draw.pixelStore; pub const viewport = draw.viewport; +pub const blitFramebuffer = draw.blitFramebuffer; pub const flush = draw.flush; pub const finish = draw.finish; diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 95910225a..31e9df4f2 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -244,7 +244,9 @@ pub fn surfaceSize(self: *const OpenGL) !struct { width: u32, height: u32 } { /// but now we need to do this manually. pub fn setViewport(self: *const OpenGL, width: u32, height: u32) void { _ = self; - gl.glad.context.Viewport.?(0, 0, @intCast(width), @intCast(height)); + gl.viewport(0, 0, @intCast(width), @intCast(height)) catch |err| { + log.warn("failed to set OpenGL viewport err={}", .{err}); + }; } /// Actions taken before doing anything in `drawFrame`. @@ -348,7 +350,7 @@ pub inline fn textureOptions(self: OpenGL) Texture.Options { return .{ .format = .rgba, .internal_format = .srgba, - .target = .@"2D", + .target = .@"2d", .min_filter = .linear, .mag_filter = .linear, .wrap_s = .clamp_to_edge, @@ -395,7 +397,7 @@ pub inline fn imageTextureOptions( return .{ .format = format.toPixelFormat(), .internal_format = if (srgb) .srgba else .rgba, - .target = .@"2D", + .target = .@"2d", // TODO: Generate mipmaps for image textures and use // linear_mipmap_linear filtering so that they // look good even when scaled way down. @@ -426,7 +428,7 @@ pub fn initAtlasTexture( .{ .format = format, .internal_format = internal_format, - .target = .Rectangle, + .target = .rectangle, .min_filter = .nearest, .mag_filter = .nearest, .wrap_s = .clamp_to_edge, diff --git a/src/renderer/opengl/Sampler.zig b/src/renderer/opengl/Sampler.zig index f4013c686..294dc1ec8 100644 --- a/src/renderer/opengl/Sampler.zig +++ b/src/renderer/opengl/Sampler.zig @@ -30,10 +30,10 @@ pub fn init( ) Error!Self { const sampler = gl.Sampler.create() catch return error.OpenGLFailed; errdefer sampler.destroy(); - sampler.parameter(.WrapS, @intFromEnum(opts.wrap_s)) catch return error.OpenGLFailed; - sampler.parameter(.WrapT, @intFromEnum(opts.wrap_t)) catch return error.OpenGLFailed; - sampler.parameter(.MinFilter, @intFromEnum(opts.min_filter)) catch return error.OpenGLFailed; - sampler.parameter(.MagFilter, @intFromEnum(opts.mag_filter)) catch return error.OpenGLFailed; + sampler.parameter(.wrap_s, opts.wrap_s) catch return error.OpenGLFailed; + sampler.parameter(.wrap_t, opts.wrap_t) catch return error.OpenGLFailed; + sampler.parameter(.min_filter, opts.min_filter) catch return error.OpenGLFailed; + sampler.parameter(.mag_filter, opts.mag_filter) catch return error.OpenGLFailed; return .{ .sampler = sampler, diff --git a/src/renderer/opengl/Target.zig b/src/renderer/opengl/Target.zig index a9649c7dc..7bc844221 100644 --- a/src/renderer/opengl/Target.zig +++ b/src/renderer/opengl/Target.zig @@ -56,23 +56,23 @@ pub fn init(opts: Options) !Self { const texture = try gl.Texture.create(); errdefer texture.destroy(); { - const bound_tex = try texture.bind(.@"2D"); + const bound_tex = try texture.bind(.@"2d"); defer bound_tex.unbind(); - try bound_tex.parameter(.MinFilter, @intFromEnum(gl.Texture.MinFilter.nearest)); - try bound_tex.parameter(.MagFilter, @intFromEnum(gl.Texture.MagFilter.nearest)); - try bound_tex.parameter(.WrapS, @intFromEnum(gl.Texture.Wrap.clamp_to_edge)); - try bound_tex.parameter(.WrapT, @intFromEnum(gl.Texture.Wrap.clamp_to_edge)); + try bound_tex.parameter(.min_filter, .nearest); + try bound_tex.parameter(.mag_filter, .nearest); + try bound_tex.parameter(.wrap_s, .clamp_to_edge); + try bound_tex.parameter(.wrap_t, .clamp_to_edge); try bound_tex.image2D( 0, .srgba, @intCast(opts.width), @intCast(opts.height), .rgba, - .UnsignedByte, + .unsigned_byte, null, ); - try bound_tex.parameter(.BaseLevel, @as(gl.c.GLint, 0)); - try bound_tex.parameter(.MaxLevel, @as(gl.c.GLint, 0)); + try bound_tex.parameter(.base_level, 0); + try bound_tex.parameter(.max_level, 0); } const fbo = try gl.Framebuffer.create(); @@ -80,7 +80,7 @@ pub fn init(opts: Options) !Self { { const bound_fbo = try fbo.bind(.framebuffer); defer bound_fbo.unbind(); - try bound_fbo.texture2D(.color0, .@"2D", texture, 0); + try bound_fbo.texture2D(.color0, .@"2d", texture, 0); switch (bound_fbo.checkStatus()) { .complete => {}, else => |status| { @@ -94,23 +94,23 @@ pub fn init(opts: Options) !Self { const export_texture = try gl.Texture.create(); errdefer export_texture.destroy(); { - const bound_tex = try export_texture.bind(.@"2D"); + const bound_tex = try export_texture.bind(.@"2d"); defer bound_tex.unbind(); - try bound_tex.parameter(.MinFilter, @intFromEnum(gl.Texture.MinFilter.nearest)); - try bound_tex.parameter(.MagFilter, @intFromEnum(gl.Texture.MagFilter.nearest)); - try bound_tex.parameter(.WrapS, @intFromEnum(gl.Texture.Wrap.clamp_to_edge)); - try bound_tex.parameter(.WrapT, @intFromEnum(gl.Texture.Wrap.clamp_to_edge)); + try bound_tex.parameter(.min_filter, .nearest); + try bound_tex.parameter(.mag_filter, .nearest); + try bound_tex.parameter(.wrap_s, .clamp_to_edge); + try bound_tex.parameter(.wrap_t, .clamp_to_edge); try bound_tex.image2D( 0, .rgba, @intCast(opts.width), @intCast(opts.height), .rgba, - .UnsignedByte, + .unsigned_byte, null, ); - try bound_tex.parameter(.BaseLevel, @as(gl.c.GLint, 0)); - try bound_tex.parameter(.MaxLevel, @as(gl.c.GLint, 0)); + try bound_tex.parameter(.base_level, 0); + try bound_tex.parameter(.max_level, 0); } const export_fbo = try gl.Framebuffer.create(); @@ -118,7 +118,7 @@ pub fn init(opts: Options) !Self { { const bound_fbo = try export_fbo.bind(.framebuffer); defer bound_fbo.unbind(); - try bound_fbo.texture2D(.color0, .@"2D", export_texture, 0); + try bound_fbo.texture2D(.color0, .@"2d", export_texture, 0); switch (bound_fbo.checkStatus()) { .complete => {}, else => |status| { diff --git a/src/renderer/opengl/Texture.zig b/src/renderer/opengl/Texture.zig index c37ec6866..52c6017cd 100644 --- a/src/renderer/opengl/Texture.zig +++ b/src/renderer/opengl/Texture.zig @@ -50,17 +50,17 @@ pub fn init( { 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.parameter(.wrap_s, opts.wrap_s) catch return error.OpenGLFailed; + texbind.parameter(.wrap_t, opts.wrap_t) catch return error.OpenGLFailed; + texbind.parameter(.min_filter, opts.min_filter) catch return error.OpenGLFailed; + texbind.parameter(.mag_filter, opts.mag_filter) catch return error.OpenGLFailed; texbind.image2D( 0, opts.internal_format, @intCast(width), @intCast(height), opts.format, - .UnsignedByte, + .unsigned_byte, if (data) |d| @ptrCast(d.ptr) else null, ) catch return error.OpenGLFailed; } @@ -98,7 +98,7 @@ pub fn replaceRegion( @intCast(width), @intCast(height), self.format, - .UnsignedByte, + .unsigned_byte, data.ptr, ) catch return error.OpenGLFailed; }