diff --git a/lib/minifb/build.zig b/lib/minifb/build.zig index 691cb34..e5be330 100644 --- a/lib/minifb/build.zig +++ b/lib/minifb/build.zig @@ -23,7 +23,7 @@ pub fn link(b: *std.build.Builder, step: *std.build.LibExeObjStep) void { step.linkLibrary(lib); } -fn fromHere(allocator: *std.mem.Allocator, path: []const u8) []const u8 { +fn fromHere(allocator: std.mem.Allocator, path: []const u8) []const u8 { const here = std.fs.path.dirname(@src().file) orelse "."; return std.fs.path.join(allocator, &.{here, path}) catch unreachable; } diff --git a/lib/minifb/src/minifb.zig b/lib/minifb/src/minifb.zig index e4a069d..b15956b 100644 --- a/lib/minifb/src/minifb.zig +++ b/lib/minifb/src/minifb.zig @@ -1,13 +1,16 @@ const std = @import("std"); -const minifb_c = @cImport({ +const c = @cImport({ @cInclude("MiniFB.h"); @cInclude("MiniFB_enums.h"); }); const testing = std.testing; -pub fn rgb(r: u8, g: u8, b: u8) u32 { - return @intCast(u32, r) << 16 | @intCast(u32, g) << 8 | b; -} +pub const Rgb = packed struct { + r: u8, + g: u8, + b: u8, + _reserved: u8 = 0, +}; pub const KeyMod = packed struct { shift: bool = false, @@ -16,20 +19,20 @@ pub const KeyMod = packed struct { super: bool = false, capsLock: bool = false, numLock: bool = false, - reserved: u26 = 0, + _reserved: u26 = 0, }; pub fn Window(comptime TUserData: type) type { - return struct { - cwin: *minifb_c.mfb_window, + return packed struct { + cwin: *c.mfb_window, - pub const UpdateError = error { + pub const UpdateError = error{ InvalidWindow, InvalidBuffer, InternalError, }; - pub const State = enum {ok, exit}; + pub const State = enum { ok, exit }; pub const OpenFlags = packed struct { resizable: bool = false, @@ -43,104 +46,112 @@ pub fn Window(comptime TUserData: type) type { pub fn open(title: [*:0]const u8, width: u32, height: u32, flags: OpenFlags) !Window(TUserData) { const intFlags = @bitCast(u32, flags); const cTitle = @as([*c]const u8, title); - const cwin: ?*minifb_c.mfb_window = minifb_c.mfb_open_ex(cTitle, width, height, intFlags); + const cwin: ?*c.mfb_window = c.mfb_open_ex(cTitle, width, height, intFlags); if (cwin) |value| { - return Window(TUserData) {.cwin=value}; + return Window(TUserData){ .cwin = value }; } else { return error.ItBroke; } - } pub fn waitSync(self: Window(TUserData)) bool { - return minifb_c.mfb_wait_sync(self.cwin); + return c.mfb_wait_sync(self.cwin); } - pub fn update(self: Window(TUserData), buffer: []u32) UpdateError!State { - const rawState = minifb_c.mfb_update(self.cwin, buffer.ptr); + pub fn update(self: Window(TUserData), buffer: []Rgb) UpdateError!State { + const rawState = c.mfb_update(self.cwin, @ptrCast(*anyopaque, buffer.ptr)); switch (rawState) { - .STATE_OK => return State.ok, - .STATE_EXIT => return State.exit, - .STATE_INVALID_WINDOW => return UpdateError.InvalidWindow, - .STATE_INVALID_BUFFER => return UpdateError.InvalidBuffer, + c.STATE_OK => return State.ok, + c.STATE_EXIT => return State.exit, + c.STATE_INVALID_WINDOW => return UpdateError.InvalidWindow, + c.STATE_INVALID_BUFFER => return UpdateError.InvalidBuffer, else => return UpdateError.InternalError, } } pub fn setUserData(self: Window(TUserData), data: *TUserData) void { - minifb_c.mfb_set_user_data(self.cwin, data); + c.mfb_set_user_data(self.cwin, data); } pub fn getUserData(self: Window(TUserData)) ?*TUserData { - return @ptrCast(?*TUserData, @alignCast(@alignOf(?*TUserData), minifb_c.mfb_get_user_data(self.cwin))); - } - - test "user data is null if never set" { - const win = try Window(u8).open("", 100, 100); - const data = win.getUserData(); - testing.expectEqual(null, data); + var cData = c.mfb_get_user_data(self.cwin); + std.log.info("@alignOf cwin={d}, addr={x}", .{ @alignOf(@TypeOf(self.cwin)), @ptrToInt(self.cwin) }); + std.log.info("@alignOf cdata={d}, addr={x}", .{ @alignOf(@TypeOf(cData)), @ptrToInt(cData) }); + return @ptrCast(?*TUserData, @alignCast(@alignOf(?*TUserData), cData)); } - test "user data is not null if previously set" { - const win = try Window(u8).open("", 100, 100); - var data: u8 = 42; - win.setUserData(&data); - testing.expectEqual(42, win.getUserData().?.*); + pub const ActiveFunc = fn (win: Window(TUserData), isActive: bool) void; + pub fn setActiveCallback(self: Window(TUserData), callback: ActiveFunc) void { + c.mfb_set_active_callback(self.cwin, @ptrCast(c.mfb_active_func, callback)); } }; } +test "user data is null if never set" { + const win = try Window(u64).open("abc", 100, 100, .{}); + const data = win.getUserData(); + try testing.expectEqual(@as(?*u64, null), data); +} + +// test "user data is not null if previously set" { +// const win = try Window(u64).open("abc", 100, 100, .{}); +// var data: u64 = 42; +// win.setUserData(&data); +// const expected: u64 = 42; +// try testing.expectEqual(expected, win.getUserData().?.*); +// } + pub fn getTargetFPS() u32 { - return minifb_c.mfb_get_target_fps(); + return c.mfb_get_target_fps(); } pub fn setTargetFPS(fps: u32) void { - minifb_c.mfb_set_target_fps(fps); + c.mfb_set_target_fps(fps); } // TODO Figure out how to run this once I have Internet access. -test "set and get target FPS" { - const max = 40; - var fps: u32 = 30; - while (fps < max) { - setTargetFPS(fps); - try std.testing.expectEqual(fps, getTargetFPS()); - } -} +// test "set and get target FPS" { +// const max = 40; +// var fps: u32 = 30; +// while (fps < max) { +// setTargetFPS(fps); +// try std.testing.expectEqual(fps, getTargetFPS()); +// } +// } -pub const Timer = struct { - ctimer: *minifb_c.mfb_timer, +pub const Timer = extern struct { + ctimer: *c.mfb_timer, pub fn init() !Timer { - const ctimer: ?*minifb_c.mfb_timer = minifb_c.mfb_timer_create(); + const ctimer: ?*c.mfb_timer = c.mfb_timer_create(); if (ctimer) |value| { - return Timer {.ctimer=value}; + return Timer{ .ctimer = value }; } else { return error.ItBroke; } } pub fn deinit(self: Timer) void { - minifb_c.mfb_timer_destroy(self.ctimer); + c.mfb_timer_destroy(self.ctimer); } pub fn reset(self: Timer) void { - minifb_c.mfb_timer_reset(self.ctimer); + c.mfb_timer_reset(self.ctimer); } pub fn now(self: Timer) f64 { - return minifb_c.mfb_timer_now(self.ctimer); + return c.mfb_timer_now(self.ctimer); } pub fn delta(self: Timer) f64 { - return minifb_c.mfb_timer_delta(self.ctimer); + return c.mfb_timer_delta(self.ctimer); } pub fn getFrequency() f64 { - return minifb_c.mfb_timer_get_frequency(); + return c.mfb_timer_get_frequency(); } pub fn getResolution() f64 { - return minifb_c.mfb_timer_get_resolution(); + return c.mfb_timer_get_resolution(); } -}; \ No newline at end of file +}; diff --git a/src/main.zig b/src/main.zig index 9fd7469..f8cf967 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,8 +6,8 @@ const max = std.math.max; const Width = 800; const Height = 600; -fn grey(value: u8) u32 { - return mfb.rgb(value, value, value); +fn grey(value: u8) mfb.Rgb { + return mfb.Rgb{ .r = value, .g = value, .b = value }; } const Coords = struct { @@ -17,45 +17,52 @@ const Coords = struct { const State = struct { period: f64, - timer: mfb.Timer, + timer: *mfb.Timer, + active: bool = true, + alloc: std.mem.Allocator, - pub fn init(period: f64) !State { - const timer = try mfb.Timer.init(); + pub fn init(alloc: std.mem.Allocator, period: f64) !State { + var timer = try alloc.create(mfb.Timer); + timer.* = try mfb.Timer.init(); return State{ - .period=period, - .timer=timer, + .period = period, + .timer = timer, + .alloc = alloc, }; } pub fn deinit(self: State) void { - self.timer.deinit(); + self.timer.*.deinit(); + self.alloc.destroy(self.timer); } pub fn render(self: State, buf: Buffer) void { - var bgValue = @rem(self.timer.now(), self.period) / self.period * 512; + var bgValue = @rem(self.timer.*.now(), self.period) / self.period * 512; if (bgValue >= 256) { bgValue = 512 - bgValue; } - buf.drawRectangle(.{.x=0,.y=0}, .{.x=Width, .y=Height}, grey(@floatToInt(u8, bgValue))); - buf.drawRectangle(.{.x=Width/3, .y=Height/3}, .{.x=2*Width/3, .y=2*Height/3}, mfb.rgb(255,0,0)); - buf.drawRectangle(.{.x=0,.y=0}, .{.x=10,.y=10}, mfb.rgb(0,0,255)); + const rectColor = if (self.active) mfb.Rgb{ .r = 0, .g = 255, .b = 0 } else mfb.Rgb{ .r = 255, .g = 0, .b = 0 }; + + buf.drawRectangle(.{ .x = 0, .y = 0 }, .{ .x = Width, .y = Height }, grey(@floatToInt(u8, bgValue))); + buf.drawRectangle(.{ .x = Width / 3, .y = Height / 3 }, .{ .x = 2 * Width / 3, .y = 2 * Height / 3 }, rectColor); + buf.drawRectangle(.{ .x = 0, .y = 0 }, .{ .x = 10, .y = 10 }, mfb.Rgb{ .r = 0, .g = 0, .b = 255 }); } }; const Buffer = struct { - alloc: *std.mem.Allocator, - slice: []u32, + alloc: std.mem.Allocator, + slice: []mfb.Rgb, width: u32, height: u32, - pub fn init(alloc: *std.mem.Allocator, width: u32, height: u32) !Buffer { - const slice = try alloc.alloc(u32, width*height); - return Buffer { - .alloc=alloc, - .slice=slice, - .width=width, - .height=height, + pub fn init(alloc: std.mem.Allocator, width: u32, height: u32) !Buffer { + const slice = try alloc.alloc(mfb.Rgb, width * height); + return Buffer{ + .alloc = alloc, + .slice = slice, + .width = width, + .height = height, }; } @@ -63,27 +70,27 @@ const Buffer = struct { self.alloc.free(self.slice); } - pub fn setPixel(self: Buffer, coords: Coords, color: u32) void { + pub fn setPixel(self: Buffer, coords: Coords, color: mfb.Rgb) void { const x = @intCast(u32, coords.x); const y = @intCast(u32, coords.y); - self.slice[y*self.width + x] = color; + self.slice[y * self.width + x] = color; } - pub fn drawRectangle(self: Buffer, a: Coords, b: Coords, color: u32) void { + pub fn drawRectangle(self: Buffer, a: Coords, b: Coords, color: mfb.Rgb) void { var start = Coords{ - .x=max(0, min(a.x, b.x)), - .y=max(0, min(a.y, b.y)), + .x = max(0, min(a.x, b.x)), + .y = max(0, min(a.y, b.y)), }; var end = Coords{ - .x=min(@intCast(i32, self.width), max(a.x, b.x)), - .y=min(@intCast(i32, self.height), max(a.y, b.y)), + .x = min(@intCast(i32, self.width), max(a.x, b.x)), + .y = min(@intCast(i32, self.height), max(a.y, b.y)), }; var y = start.y; while (y < end.y) { var x = start.x; while (x < end.x) { - self.setPixel(.{.x=x, .y=y}, color); + self.setPixel(.{ .x = x, .y = y }, color); x += 1; } y += 1; @@ -91,17 +98,34 @@ const Buffer = struct { } }; +fn handleActive(win: mfb.Window(State), isActive: bool) void { + // win.getUserData().?.*.active = isActive; + var data = win.getUserData(); + std.log.info("got data", .{}); + if (data) |value| { + // value.*.active = isActive; + _ = value; + } + if (isActive) { + std.log.info("activated!!!!!!!!!!!!", .{}); + } else { + std.log.info("deactivated", .{}); + } +} + pub fn main() !void { var gp_allocator = std.heap.GeneralPurposeAllocator(.{}){}; - const alloc = &gp_allocator.allocator; + const alloc = gp_allocator.allocator(); - var state = try State.init(3); + var state = try State.init(alloc, 3); defer state.deinit(); - var win = mfb.Window(State).open("Hello minifb-zig", Width, Height, .{.resizable=true}) catch unreachable; + var win = mfb.Window(State).open("Hello minifb-zig", Width, Height, .{ .resizable = true, .alwaysOnTop = true }) catch unreachable; mfb.setTargetFPS(7); win.setUserData(&state); + win.setActiveCallback(handleActive); + var buf = try Buffer.init(alloc, Width, Height); defer buf.deinit(); @@ -109,6 +133,7 @@ pub fn main() !void { if (aliasedState) |value| { std.log.info("Period: {d}", .{value.*.period}); } + state.render(buf); while (win.waitSync()) { state.render(buf);