const std = @import("std"); const sdl = @import("sdl2"); const zlm = @import("zlm"); const gl = @import("zgl"); const m = zlm.SpecializeOn(f32); const Self = @This(); window: sdl.Window, context: sdl.gl.Context, //color_loc: u32, buffer: gl.Buffer, color: [4]f32, test_counter: usize = 0, vbo: [max_objects]f32 = .{0.0} ** max_objects, colors: [max_objects][4]f32 = .{[4]f32{ 0.0, 0.0, 0.0, 1.0 }} ** max_objects, vbo_index: usize = 0, const max_objects: usize = 16384; pub fn init() !Self { try sdl.init(.{ .video = true, .audio = true, .events = true }); try sdl.gl.setAttribute(.{ .context_major_version = 3 }); try sdl.gl.setAttribute(.{ .context_minor_version = 3 }); try sdl.gl.setAttribute(.{ .multisamplebuffers = true }); try sdl.gl.setAttribute(.{ .multisamplesamples = 4 }); const window = try sdl.createWindow( "USG", .{ .centered = {} }, .{ .centered = {} }, 1280, 720, .{ .context = .opengl, .vis = .shown }, ); const ctx = try sdl.gl.createContext(window); sdl.gl.setSwapInterval(.immediate) catch { std.debug.print("WARNING: Unable to configure the swap interval.\n", .{}); }; // Shader stuff var mvp_loc: u32 = undefined; //var color_loc: u32 = undefined; const program = gl.Program.create(); { const vs = gl.Shader.create(.vertex); defer vs.delete(); const fs = gl.Shader.create(.fragment); defer fs.delete(); vs.source(1, &.{@embedFile("shaders/vector.vs")}); fs.source(1, &.{@embedFile("shaders/fragment.fs")}); vs.compile(); fs.compile(); program.attach(vs); defer program.detach(vs); program.attach(fs); defer program.detach(fs); program.link(); mvp_loc = program.uniformLocation("mvp").?; //color_loc = program.uniformLocation("color").?; } program.use(); // Get the matrix that converts coordinates to 1:1 on the screen from the OpenGL default { const wsize = window.getSize(); const xunit = @intToFloat(f32, wsize.width); const yunit = @intToFloat(f32, wsize.height); const ortho = m.Mat4.createOrthogonal(0.0, xunit, yunit, 0.0, 0.0, 100.0); gl.uniformMatrix4fv(mvp_loc, false, &.{ortho.fields}); } var vertex_array = gl.VertexArray.gen(); vertex_array.bind(); const buf = gl.Buffer.gen(); buf.bind(.array_buffer); gl.vertexAttribPointer(0, 2, .float, false, @sizeOf(f32) * 6, @sizeOf(f32) * 0); gl.enableVertexAttribArray(0); gl.vertexAttribPointer(1, 4, .float, false, @sizeOf(f32) * 6, @sizeOf(f32) * 2); gl.enableVertexAttribArray(1); gl.clearColor(0.91, 0.97, 1.00, 1.00); // TODO: See if there's a more optimal solution to this, maybe activating only when necessary gl.enable(.blend); gl.blendFunc(.src_alpha, .one_minus_src_alpha); return Self{ .window = window, .context = ctx, .buffer = buf, .color = .{ 0, 0, 0, 0 } }; } pub fn render(self: *Self) void { std.debug.print("Number of rendered elements: {}\n", .{self.test_counter}); self.test_counter = 0; self.buffer.data(f32, &self.vbo, .static_draw); // { // var i: usize = 0; // while (i < self.vbo_index) { // gl.uniform4fv(self.color_loc, &.{self.colors[i]}); // //std.debug.print("Color: {any}\n", .{self.colors[i]}); // gl.drawArrays(.triangles, i, 12); // i += 12; // } // } gl.drawArrays(.triangles, 0, self.vbo_index); self.vbo_index = 0; sdl.gl.swapWindow(self.window); gl.clear(.{ .color = true }); } pub fn deinit(self: *Self) void { gl.disableVertexAttribArray(0); sdl.quit(); self.window.destroy(); sdl.gl.deleteContext(self.context); } pub fn setColor(self: *Self, r: u8, g: i32, b: i32, a: i32) void { self.*.color = .{ @intToFloat(f32, r) / 255.0, @intToFloat(f32, g) / 255.0, @intToFloat(f32, b) / 255.0, @intToFloat(f32, a) / 255.0, }; } pub fn drawRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void { //const indices = [_]u8{ 0, 1, 1, 2, 2, 3, 3, 0 }; //self.renderRectangle(x, y, w, h, .lines, &indices); _ = x; _ = y; _ = self; _ = w; _ = h; } pub fn fillRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void { //const indices = [_]u8{ 1, 3, 0, 1, 3, 2 }; self.renderRectangle(x, y, w, h); } fn renderRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void { self.test_counter += 1; //gl.uniform4fv(self.color_loc, &.{self.color}); var xf = @intToFloat(f32, x); var yf = @intToFloat(f32, y); var wf = @intToFloat(f32, w); var hf = @intToFloat(f32, h); const i = self.vbo_index; const vertex_data = [36]f32{ xf, yf, // up-left self.color[0], self.color[1], self.color[2], self.color[3], xf + wf, yf, // up-right self.color[0], self.color[1], self.color[2], self.color[3], xf, yf + hf, self.color[0], self.color[1], self.color[2], self.color[3], xf + wf, yf + hf, // down-right self.color[0], self.color[1], self.color[2], self.color[3], xf + wf, yf, self.color[0], self.color[1], self.color[2], self.color[3], xf, yf + hf, // down-left self.color[0], self.color[1], self.color[2], self.color[3], }; std.mem.copy(f32, self.vbo[i .. i + 36], &vertex_data); self.vbo_index += 36; } pub const OutputSize = struct { width: c_int, height: c_int }; pub fn getOutputSize(self: Self) OutputSize { var wsize = self.window.getSize(); return OutputSize{ .width = wsize.width, .height = wsize.height, }; }