From aab0eb62f20faa387aa5f434bd9fc671bf02ca42 Mon Sep 17 00:00:00 2001 From: Emi Gutekanst Date: Fri, 10 Jan 2025 20:10:58 -0700 Subject: [PATCH] {gfx,module}: fix Text update bug caused by anyUpdate reset, add peekAnyUpdate/peekUpdate Signed-off-by: Emi Gutekanst --- src/gfx/Text.zig | 2 +- src/module.zig | 32 +++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/gfx/Text.zig b/src/gfx/Text.zig index 72231d94..c2a6dd07 100644 --- a/src/gfx/Text.zig +++ b/src/gfx/Text.zig @@ -259,7 +259,7 @@ pub fn tick(text: *Text, core: *mach.Core) !void { const any_updated = blk: { for (pipeline_children.items) |text_id| { if (!text.objects.is(text_id)) continue; - if (text.objects.anyUpdated(text_id)) break :blk true; + if (text.objects.peekAnyUpdated(text_id)) break :blk true; } break :blk false; }; diff --git a/src/module.zig b/src/module.zig index 0196504d..b3b57360 100644 --- a/src/module.zig +++ b/src/module.zig @@ -311,23 +311,43 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type { } /// If options have tracking enabled, this returns true when the given field has been set - /// using the set() or setAll() methods. A subsequent call to .updated() or .anyUpdated() + /// using the set() or setAll() methods. A subsequent call to .updated(), .anyUpdated(), etc. /// will return false until another set() or setAll() call is made. pub fn updated(objs: *@This(), id: ObjectID, field_name: anytype) bool { + return objs.updatedOptions(id, field_name, false); + } + + /// Same as updated(), but doesn't alter the behavior of subsequent .updated(), .anyUpdated(), + /// etc. calls + pub fn peekUpdated(objs: *@This(), id: ObjectID, field_name: anytype) bool { + return objs.updatedOptions(id, field_name, true); + } + + inline fn updatedOptions(objs: *@This(), id: ObjectID, field_name: anytype, comptime peek: bool) bool { if (!options.track_fields) return false; const unpacked = objs.validateAndUnpack(id, "updated"); const field_index = std.meta.fieldIndex(T, @tagName(field_name)).?; const updated_fields = &(objs.internal.updated orelse return false); const updated_index = unpacked.index * @typeInfo(T).@"struct".fields.len + field_index; const updated_value = updated_fields.isSet(updated_index); - updated_fields.unset(updated_index); + if (!peek) updated_fields.unset(updated_index); return updated_value; } /// If options have tracking enabled, this returns true when any field has been set using - /// the set() or setAll() methods. A subsequent call to .updated() or .anyUpdated() will + /// the set() or setAll() methods. A subsequent call to .updated(), .anyUpdated(), etc. will /// return false until another set() or setAll() call is made. pub fn anyUpdated(objs: *@This(), id: ObjectID) bool { + return objs.anyUpdatedOptions(id, false); + } + + /// Same as anyUpdated(), but doesn't alter the behavior of subsequent .updated(), .anyUpdated(), + /// etc. calls + pub fn peekAnyUpdated(objs: *@This(), id: ObjectID) bool { + return objs.anyUpdatedOptions(id, true); + } + + inline fn anyUpdatedOptions(objs: *@This(), id: ObjectID, comptime peek: bool) bool { if (!options.track_fields) return false; const unpacked = objs.validateAndUnpack(id, "updated"); const updated_fields = &(objs.internal.updated orelse return false); @@ -335,10 +355,8 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type { inline for (0..@typeInfo(T).@"struct".fields.len) |field_index| { const updated_index = unpacked.index * @typeInfo(T).@"struct".fields.len + field_index; const updated_value = updated_fields.isSet(updated_index); - updated_fields.unset(updated_index); - if (updated_value) { - any_updated = true; - } + if (!peek) updated_fields.unset(updated_index); + if (updated_value) any_updated = true; } return any_updated; }