const std = @import("std"); const debug = std.debug; const panic = debug.panic; const c = @import("c.zig"); const debug_gl = @import("debug_gl.zig"); const cfg = @import("config.zig"); const out = @import("output.zig"); const gl = @import("gl.zig"); const ctrl = @import("control.zig"); const c_allocator = std.heap.c_allocator; var window: *c.GLFWwindow = undefined; fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { panic("Error {}: {s}\n", .{ err, description }); } pub fn main() !void { const progress = std.Progress.start(.{}); defer progress.end(); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const cfg_allocator = arena.allocator(); defer arena.deinit(); var config = try cfg.Config.init(cfg_allocator); _ = c.glfwSetErrorCallback(errorCallback); if (c.glfwInit() == c.GL_FALSE) { panic("GLFW init failure\n", .{}); } defer c.glfwTerminate(); var monitor_count: c_int = 0; const monitors = c.glfwGetMonitors(&monitor_count); for (monitors[0..@as(usize, @intCast(monitor_count))], 0..) |monitor, i| { debug.print( "monitor {}: '{s}'\n", .{ i, @as([*:0]const u8, @ptrCast(c.glfwGetMonitorName(monitor))) }, ); } c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4); c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 2); c.glfwWindowHint(c.GLFW_OPENGL_FORWARD_COMPAT, c.GL_TRUE); c.glfwWindowHint(c.GLFW_OPENGL_DEBUG_CONTEXT, debug_gl.is_on); c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE); c.glfwWindowHint(c.GLFW_DEPTH_BITS, 0); c.glfwWindowHint(c.GLFW_STENCIL_BITS, 0); c.glfwWindowHint(c.GLFW_VISIBLE, c.GLFW_FALSE); window = c.glfwCreateWindow(config.width, config.height, "glsl-view", null, null) orelse { panic("unable to create window\n", .{}); }; defer c.glfwDestroyWindow(window); c.glfwMakeContextCurrent(window); c.glfwSwapInterval(1); var constants = try gl.Constants.create(window, &config); defer constants.destroy(); var outputs = try std.ArrayList(*out.Output).initCapacity(cfg_allocator, config.outputs.len); defer outputs.deinit(); for (config.outputs) |*output_config| { outputs.appendAssumeCapacity(try out.Output.create(cfg_allocator, output_config, &constants)); } defer for (outputs.items) |output| { output.destroy(cfg_allocator); }; c.glfwMakeContextCurrent(window); c.glClearColor(0.0, 0.0, 0.0, 1.0); debug_gl.assertNoError(); debug_gl.init(); const start_time = c.glfwGetTime(); var prev_time = start_time; constants.normalized_quad.bind(0); var main_program = try gl.ShaderProgram.create( \\#version 330 core \\ \\layout(location = 0) in vec2 position; \\out vec2 uv; \\ \\void main() { \\ uv = position / 2.0 + 0.5; \\ gl_Position = vec4(position, 0, 1); \\} , \\#version 330 core \\ \\in vec2 uv; \\out vec4 color; \\ \\void main() { \\ vec2 check = floor(uv*10); \\ color = vec4(vec3(mod(check.x+check.y, 2.0)), 1); \\} ); defer main_program.destroy(); var fbo = try gl.FramebufferObject.create(config.width, config.height); defer fbo.destroy(); // const shader_file = try std.fs.cwd().openFile(config.fragment, .{}); // var last_stat = try shader_file.stat(); // try main_program.loadFile(config.fragment, last_stat.size); var cache = gl.UniformCache.init(std.heap.c_allocator, &main_program); defer cache.deinit(); const control = try ctrl.ControlServer.init(cfg_allocator, progress, &cache, &config, &constants); defer control.destroy(); while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { c.glfwMakeContextCurrent(window); const now_time = c.glfwGetTime(); prev_time = now_time; control.update(); // const stat = try shader_file.stat(); // if (stat.mtime > last_stat.mtime or control.reload_requested) { // try main_program.loadFile(config.fragment, stat.size); // try cache.refresh(); // last_stat = stat; // // control.reload_requested = false; // } fbo.bind(); c.glClear(c.GL_COLOR_BUFFER_BIT); main_program.bind(); constants.normalized_quad.draw(); fbo.unbind(); for (outputs.items, 0..) |output, i| { const close = output.update(fbo.texture_id); if (close) { const removed = outputs.swapRemove(i); removed.destroy(cfg_allocator); break; } } if (outputs.items.len == 0) break; c.glfwMakeContextCurrent(window); c.glfwSwapBuffers(window); c.glfwPollEvents(); } }