Skip to content

Commit

Permalink
feat: add root module, threaded buffer to file storage
Browse files Browse the repository at this point in the history
  • Loading branch information
guidoschmidt committed Oct 16, 2024
1 parent a4d42df commit dbbe873
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 5 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@
[submodule "libs/zig-gamedev"]
path = libs/zig-gamedev
url = git@github.com:zig-gamedev/zig-gamedev.git
[submodule "examples/zig.opengl/libs/zigglgen"]
path = examples/zig.opengl/libs/zigglgen
url = git@github.com:castholm/zigglgen.git
[submodule "examples/zig.opengl/libs/zig-gamedev"]
path = examples/zig.opengl/libs/zig-gamedev
url = git@github.com:zig-gamedev/zig-gamedev.git
4 changes: 4 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

_ = b.addModule("root", .{
.root_source_file = b.path("./zig/root.zig"),
});

const exe = b.addExecutable(.{
.root_source_file = b.path("zig/main.zig"),
.name = "zipper",
Expand Down
7 changes: 6 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
.{
.name = "zipper",
.version = "0.1.0",
.paths = .{ "" },
.paths = .{
"src",
"build.zig",
"build.zig.zon",
"README.md",
},
.dependencies = .{
.tokamak = .{
.url = "https://github.com/guidoschmidt/tokamak/archive/93b977bc10b5a2002cdb2dc4a80fc008d010915b.tar.gz",
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion example/index.ts → examples/web.canvas/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { saveCanvasToBackendWithWorker } from "../ts/zipper";
import { saveCanvasToBackendWithWorker } from "../../ts/zipper";

const workerUrl = new URL("./worker", import.meta.url);

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
38 changes: 38 additions & 0 deletions examples/zig.opengl/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const exe = b.addExecutable(.{
.name = "zipper.opengl",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});

b.installArtifact(exe);

// zglfw: zig-gamedev
const zglfw = b.dependency("zglfw", .{});
exe.root_module.addImport("zglfw", zglfw.module("root"));
exe.linkLibrary(zglfw.artifact("glfw"));

// OpenGL bindings: zigglgen
const gl_bindings = @import("zigglgen").generateBindingsModule(b, .{
.api = .gl,
.version = .@"4.0",
.profile = .core,
.extensions = &.{}
});
exe.root_module.addImport("gl", gl_bindings);

// Zipper
const zipper = b.dependency("zipper", .{});
exe.root_module.addImport("zipper", zipper.module("root"));

const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
20 changes: 20 additions & 0 deletions examples/zig.opengl/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.{
.name = "zig.opengl",
.version = "0.0.0",
.dependencies = .{
.zipper = .{
.path = "../../",
},
.zigglgen = .{
.path = "./libs/zigglgen",
},
.zglfw = .{
.path = "./libs/zig-gamedev/libs/zglfw",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}
1 change: 1 addition & 0 deletions examples/zig.opengl/libs/zig-gamedev
Submodule zig-gamedev added at d96ecc
1 change: 1 addition & 0 deletions examples/zig.opengl/libs/zigglgen
Submodule zigglgen added at e46b14
68 changes: 68 additions & 0 deletions examples/zig.opengl/src/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const std = @import("std");
const zglfw = @import("zglfw");
const gl = @import("gl");
const zipper = @import("zipper");

fn getProcAddress(prefixed_name: [*:0]const u8) ?gl.PROC {
return @alignCast(zglfw.getProcAddress(std.mem.span(prefixed_name)));
}

pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();

var procs: gl.ProcTable = undefined;

try zglfw.init();
const window = try zglfw.Window.create(300, 300, "zipper-opengl", null);
defer window.destroy();
zglfw.makeContextCurrent(window);

if (!procs.init(getProcAddress)) return error.InitFailed;
gl.makeProcTableCurrent(&procs);
defer gl.makeProcTableCurrent(null);

const size = window.getFramebufferSize();
const width = size[0];
const height = size[1];

var r: f32 = 0.0;
var g: f32 = 0.0;
var b: f32 = 0.0;

var is_recording = false;
var frame: usize = 0;
var pixels: []u8 = try allocator.alloc(u8, @as(usize, @intCast(width)) * @as(usize, @intCast(height)) * 4);
try zipper.init(allocator, "zig-opengl", "zipper-examples");
defer zipper.deinit();

while (!window.shouldClose() and window.getKey(.escape) != .press) {
gl.ClearColor(r, g, b, 1.0);
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

if (window.getKey(.r) == .press) {
is_recording = true;
}
if (window.getKey(.s) == .press) {
is_recording = false;
}

if (is_recording) {
std.debug.print("\nSaving frame {d}...", .{ frame });
gl.ReadPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, @ptrCast(pixels[0..]));
try zipper.putPixels(pixels[0..], width, height, frame);
frame += 1;
}

zglfw.pollEvents();
window.swapBuffers();

r += 0.005;
g += 0.007;
b += 0.009;
r = @mod(r, 1.0);
g = @mod(g, 1.0);
b = @mod(b, 1.0);
}
}
22 changes: 19 additions & 3 deletions zig/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const b64 = std.base64;
const b64_decoder = b64.standard.Decoder;

var temp_buffer: [256]u8 = undefined;
var image_data_buffer: std.ArrayList(ImageData) = undefined;
var storage_thread: std.Thread = undefined;

pub const ImageData = struct {
frame_num: usize,
Expand All @@ -21,7 +23,7 @@ pub const ImageData = struct {
};

fn storeImage(allocator: Allocator, image_data: ImageData) !void {
const subpath = try std.fmt.bufPrintZ(&temp_buffer, "./imgdata/{s}/", .{image_data.foldername});
const subpath = try std.fmt.bufPrintZ(&temp_buffer, "./imgdata/{s}", .{image_data.foldername});
try cwd.makePath(subpath);
const output_file = std.fmt.allocPrintZ(allocator, "{s}/{s}_{d:0>8}.{s}", .{
subpath, image_data.filename, image_data.frame_num, image_data.ext,
Expand Down Expand Up @@ -54,6 +56,14 @@ fn storeImage(allocator: Allocator, image_data: ImageData) !void {
// try out_file.writeAll(data_decoded);
}

fn storeBuffers(allocator: Allocator) !void {
while(true) {
if (image_data_buffer.items.len == 0) continue;
const next = image_data_buffer.pop();
try storeImage(allocator, next);
}
}

pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
Expand All @@ -63,6 +73,11 @@ pub fn main() !void {
zstbi.setFlipVerticallyOnWrite(true);
defer zstbi.deinit();

image_data_buffer = std.ArrayList(ImageData).init(allocator);
defer image_data_buffer.deinit();

storage_thread = try std.Thread.spawn(.{}, storeBuffers, .{ allocator });

const port: u16 = 8000;
std.debug.print("\nRunnig tokamak\n>>> http://127.0.0.1:{d}", .{port});

Expand All @@ -84,9 +99,10 @@ const routes: []const tk.Route = &.{
};

const api = struct {
pub fn @"POST /"(req: *tk.Request, allocator: std.mem.Allocator, image_data: ImageData) !u32 {
pub fn @"PUT /"(req: *tk.Request, _: std.mem.Allocator, image_data: ImageData) !u32 {
_ = req;
try storeImage(allocator, image_data);
try image_data_buffer.append(image_data);
// try storeImage(allocator, image_data);
return 200;
}
};
69 changes: 69 additions & 0 deletions zig/root.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const std = @import("std");
const ImageData = @import("main.zig").ImageData;

var allocator: std.mem.Allocator = undefined;
var file_prefix: []const u8 = undefined;
var foldername: []const u8 = undefined;

const max_threads = 8;
var buffers: [max_threads]std.ArrayList(ImageData) = undefined;
var background_threads: std.ArrayList(std.Thread) = undefined;

pub fn init(alloc: std.mem.Allocator, filename: []const u8, folder: []const u8) !void {
allocator = alloc;
file_prefix = filename;
foldername = folder;
background_threads = std.ArrayList(std.Thread).init(allocator);
for(0..max_threads) |i| {
buffers[i] = std.ArrayList(ImageData).init(allocator);
const t = try std.Thread.spawn(.{}, sendPayloads, .{ i });
try background_threads.append(t);
}
}

pub fn deinit() void {
for (buffers) |b| b.deinit();
for(background_threads.items) |t| t.detach();
}

pub fn putPixels(pixels: []u8, width: i32, height: i32, frame: usize) !void {
const payload = ImageData {
.frame_num = frame,
.ext = "png",
.filename = file_prefix,
.foldername = foldername,
.imageData = pixels,
.width = width,
.height = height,
};
try buffers[@mod(frame, max_threads)].append(payload);
}

fn sendPayloads(buffer_idx: usize) !void {
while(true) {
if (buffers[buffer_idx].items.len == 0) continue;
const payload = buffers[buffer_idx].pop();
std.debug.print("\n>>> Sending {s} #{d}", .{ payload.filename, payload.frame_num });

var string_stream = std.ArrayList(u8).init(allocator);
defer string_stream.deinit();
try std.json.stringify(payload, .{}, string_stream.writer());

var body = std.ArrayList(u8).init(allocator);
defer body.deinit();

var http_client = std.http.Client { .allocator = allocator };
defer http_client.deinit();
const request = try http_client.fetch(.{
.method = .PUT,
.location = .{ .url = "http://127.0.0.1:8000" },
.response_storage = .{
.dynamic = &body,
},
.payload = string_stream.items,
});
if (request.status != .ok) {
std.debug.print("\nError on sending request: {any}", .{ request.status });
}
}
}

0 comments on commit dbbe873

Please sign in to comment.