}
};
- // Dynamically load things in the binary
- {
- use type_info;
-
- // Look through all the types in the program
- for type: type_table {
- if type.kind != .Struct do continue;
-
- ts := cast(^Type_Info_Struct) type;
- if !string.starts_with(ts.name, "Feature_") do continue;
-
- // Any types that are a structure and start with "Feature_" will be dynamically loaded
-
- debug_log(.Info, "Found feature '{}'", string.advance(ts.name, 8));
-
- for ^member: ts.members {
- Hook_Function_Type :: #type () -> void;
-
- if member.name == "setup" {
- assert(member.type == Hook_Function_Type, "setup has the wrong type.");
- assert(member.default != null, "setup has no default function.");
-
- (*(cast(^Hook_Function_Type) member.default))();
- }
- }
- }
- }
+ invoke_feature_function("setup");
load_background_tile_texture :: () {
background_tile_texture = gfx.load_texture(32, 32, #file_contents "res/images/background_tile.data", gl.RGB, gl.RGB);
gfx.set_texture();
}
}
+
+@Relocate // This should be moved to somewhere else when the code base.
+invoke_feature_function :: macro (name: str, Hook_Type := #type () -> void, call := #code f()) {
+ use type_info;
+
+ #persist features : [..] ^type_info.Type_Info_Struct;
+ if features.data == null {
+ debug_log(.Info, "Getting list of loaded features.");
+
+ array.init(^features);
+
+ for type: type_table {
+ if type.kind != .Struct do continue;
+
+ feature := cast(^Type_Info_Struct) type;
+ if !string.starts_with(feature.name, "Feature_") do continue;
+
+ features << feature;
+ }
+ }
+
+ for feature: features {
+ for ^member: feature.members {
+ if member.name == name {
+ #if config.DEBUG {
+ buffer: [256] u8;
+ assert(member.type == Hook_Type, conv.str_format(buffer, "'{}' has the wrong type.", name));
+ assert(member.default != null, conv.str_format(buffer, "'{}' has no default function.", name));
+ }
+
+ f := *(cast(^Hook_Type) member.default);
+ #insert call;
+ }
+ }
+ }
+}