dropping all updates
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 22 Feb 2022 01:56:10 +0000 (19:56 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 22 Feb 2022 01:56:10 +0000 (19:56 -0600)
13 files changed:
docs/items.md [new file with mode: 0644]
run_tree/scenes/default.items [new file with mode: 0644]
run_tree/scenes/quick_save.scene
src/build.onyx
src/entity/editor.onyx
src/entity/items.onyx
src/entity/manager.onyx
src/entity/player.onyx
src/entity/store.onyx
src/game.onyx
src/gfx/texture.onyx
src/utils/any_utils.onyx [new file with mode: 0644]
src/utils/asset_loader.onyx [new file with mode: 0644]

diff --git a/docs/items.md b/docs/items.md
new file mode 100644 (file)
index 0000000..7565c69
--- /dev/null
@@ -0,0 +1,15 @@
+Items
+-----
+
+Items in this game will be defined in a file, or a set of files.
+They will have the following properties:
+     - unique id
+     - display name
+     - texture (or some way of drawing the item)
+
+The file that the items will be stored in will have a similar format
+to the entity scene format:
+
+item_id:
+name="Test"
+texture="./assets/..."
diff --git a/run_tree/scenes/default.items b/run_tree/scenes/default.items
new file mode 100644 (file)
index 0000000..f9d6bf4
--- /dev/null
@@ -0,0 +1,5 @@
+:beer
+name="Beer"
+weight=12.34
+
+
index 9a525a6d6c08d7257c977586b67a85daa932e82c..17de2c490f8e49e8c890b5e408de0f5d5de4bdc8 100644 (file)
@@ -47,7 +47,7 @@ entity.size.x = 370.0000
 entity.size.y = 24.0000
 target_openness = 0.8000
 
-:Item
+:Item_Entity
 entity.id = 4
 entity.flags = 0
 entity.pos.x = 891.5230
@@ -59,7 +59,7 @@ color.g = 0.0000
 color.b = 1.0000
 color.a = 1.0000
 
-:Item
+:Item_Entity
 entity.id = 5
 entity.flags = 4
 entity.pos.x = 167.6909
index 013b443f8e30ef9fd97bda3459f8a67e4b23cc0f..c88630770cfd025b1f3f5dbe1382876c34ecdc19 100644 (file)
@@ -30,6 +30,8 @@ DEBUG :: false
 #load "gfx/texture"
 #load "gfx/ui"
 
+#load "utils/any_utils"
+#load "utils/asset_loader"
 #load "utils/input"
 #load "utils/vecmath"
 
index 089a33fb39853fdeabf069991855c2c7fd46fb17..93cf7918ad1c9d946499aeb6972576eb656a1ff7 100644 (file)
@@ -4,15 +4,16 @@
 //
 // - [x] Create new entity
 // - [ ] Edit entity properties in UI
-// - [ ] Serialize / Deserialize a scene
+// - [x] Serialize / Deserialize a scene
 //
 
 use package core
 use package opengles
 use package glfw3
 
-Editor_Range    :: struct {min, max: f32;}
-Editor_Disabled :: struct {}
+Editor_Range        :: struct {min, max: f32;}
+Editor_Disabled     :: struct {}
+Editor_Custom_Field :: struct { func: () -> void; }
 
 editor_init :: () {
     editor_font = font_lookup(.{"./assets/fonts/calibri.ttf", 18});
@@ -107,6 +108,11 @@ editor_update :: (dt: f32) {
         if resizing {
             selected_entity.size += mouse_get_delta_vector();
         }
+
+        if is_key_just_down(GLFW_KEY_DELETE) {
+            scene->delete(selected_entity);
+            selected_entity_id = Entity_Nothing;
+        }
     }
 }
 
@@ -212,6 +218,11 @@ editor_draw :: () {
     info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(entity.type);
 
     font_print(editor_big_font, x + 2, y + 24, info.name);
+    if draw_button(.{ x + w - 150, y, 150, 24 }, "Delete") {
+        scene->delete(entity);
+        selected_entity_id = Entity_Nothing;
+        return;
+    }
 
     if active_index >= 0 do sidebar_width += w;
     render_struct_fields(any.{~~entity, entity.type}, 0, x, y + 4, w, h);
index e0fa2e23e0f2c3e638cebb7aae4d7bd0875c5118..e6c5b504929c6dc19cd4737e1338a145197ccbdc 100644 (file)
@@ -1,9 +1,93 @@
 
 use package core
 
+
 Item :: struct {
+    name: str;
+    weight := 10.0f;
+
+    color := Color.{ 1, 1, 0 };
+}
+
+Item_Store :: struct {
+    item_allocator: Allocator;
+    items: Map(str, ^Item);
+
+    load_items_from_file :: item_store_load_items_from_file;
+}
+
+item_store_make :: () -> Item_Store {
+    is: Item_Store;
+    is.item_allocator = context.allocator;
+    map.init(^is.items);
+
+    return is;
+}
+
+item_store_load_items_from_file :: (use this: ^Item_Store, path: str) {
+    @CopyNPaste // from entity/store.onyx
+
+    err, input_file := os.open(path, .Read);
+    if err != .None {
+        printf("Failed to open file: {}\n", path);
+        return;
+    }
+    defer os.close(^input_file);
+    reader := io.reader_make(^input_file);
+
+    use type_info;
+
+    current_item: ^Item;
+
+    line_number := 1;
+    while !io.reader_empty(^reader) {
+        defer line_number += 1;
+
+        line := io.read_line(^reader, inplace=true);
+        if line.count <= 1 do continue;
+
+        if line[0] == #char ":" {
+            item_id := string.advance(line)
+                    |> string.strip_whitespace();
+
+            if items->has(item_id) {
+                printf("Duplicate definition for item with id '{}', on line: {}.\n", item_id);
+                return;
+            }
+
+            item_id = string.alloc_copy(item_id, allocator=item_allocator);
+
+            current_item = new(Item, allocator=item_allocator);
+            items[item_id] = current_item;
+            continue;
+        }
+
+        if current_item == null do continue;
+
+        var_name := string.read_until(^line, #char "=")
+                 |> string.strip_whitespace();
+        string.advance(^line, 1);
+        string.strip_whitespace(^line);
+
+        member := get_any_for_member(ptr_to_any(current_item), var_name);
+        if member.data == null {
+            printf("'{}' is not a valid member of Item on line {}.\n", var_name, line_number);
+            continue;
+        }
+
+        if !conv.parse_any(member.data, member.type, line) {
+            printf("Unable to parse '{}' for type '{}' on line {}.\n", line, member.type, line_number);
+            continue;
+        }
+    }
+}
+
+
+Item_Entity :: struct {
     use entity: Entity;
 
+    [Editor_Custom_Field.{render_item_picker}]
+    item: str;
     color: Color;
 
     init_data :: struct {
@@ -11,7 +95,7 @@ Item :: struct {
         color := Color.{1, 0, 1, 1};
     }
 
-    init :: (use this: ^Item, data: init_data) {
+    init :: (use this: ^Item_Entity, data: init_data) {
         this.pos   = data.pos;
         this.size  = .{16, 16};
         this.color = data.color;
@@ -20,10 +104,17 @@ Item :: struct {
 
     get_rect :: Entity.get_rect
 
-    draw :: (use this: ^Item) {
+    draw :: (use this: ^Item_Entity) {
         immediate_set_color(this.color);
 
         r := this->get_rect();
         immediate_rectangle(r.x, r.y, r.w, r.h);
     }
 }
+
+
+#local {
+    render_item_picker :: () {
+        
+    }
+}
\ No newline at end of file
index 68aca33b0fafffc3ec15b81e0ff2e7cc76aaf5f2..6a157d0b107b87d638ae10210546a80091dd906d 100644 (file)
@@ -43,6 +43,7 @@ IsEntity :: interface (e: $E) {
 Entity_Info :: struct {
     create_default : (scene: ^Entity_Manager) -> ^Entity = null_proc;
 
+    destroy  : (entity: ^Entity) -> void                      = null_proc;
     update   : (entity: ^Entity, dt: f32) -> void             = null_proc;
     draw     : (entity: ^Entity) -> void                      = null_proc;
     get_rect : (entity: ^Entity) -> Rect                      = null_proc;
@@ -66,6 +67,7 @@ Entity_Manager :: struct {
     update         :: entity_manager_update;
     draw           :: entity_manager_draw;
     get            :: entity_manager_get;
+    delete         :: entity_manager_delete;
     query          :: entity_manager_query;
     query_by_type  :: entity_manager_query_by_type;
     query_by_flags :: entity_manager_query_by_flags;
@@ -116,6 +118,7 @@ entity_manager_register :: (use this: ^Entity_Manager, $entity_type: type_expr)
         @CompilerFeatures // Maybe there should be data stored in the Type_Info_Struct about
         // the functions/methods that are defined in the structs scope. I don't know if that
         // would be worthwhile or if it would just be bulking up the type info data.
+        #if #defined(entity_type.destroy)  { info.destroy  = entity_type.destroy;  if DEBUG do printf("{} has '{}'.\n", entity_type, "destroy"); }
         #if #defined(entity_type.update)   { info.update   = entity_type.update;   if DEBUG do printf("{} has '{}'.\n", entity_type, "update"); }
         #if #defined(entity_type.draw)     { info.draw     = entity_type.draw;     if DEBUG do printf("{} has '{}'.\n", entity_type, "draw"); }
         #if #defined(entity_type.get_rect) { info.get_rect = entity_type.get_rect; if DEBUG do printf("{} has '{}'.\n", entity_type, "get_rect"); }
@@ -178,6 +181,12 @@ entity_manager_draw :: (use this: ^Entity_Manager) {
 
 entity_manager_get :: (use this: ^Entity_Manager, id: Entity_ID) => entity_map[id];
 
+entity_manager_delete :: (use this: ^Entity_Manager, ent: ^Entity) {
+    map.delete(^entity_map, ent.id);
+    array.remove(^entities, ent); // This preserves the order of the entities, but does that matter?
+    raw_free(entity_allocator, ent);
+}
+
 entity_manager_query :: (use this: ^Entity_Manager, area: Rect) -> [] ^Entity {
     ents: [..] ^Entity;
     for entities {
index 5a3f091212b47342a11dcfcc3dbaa4edd5dad02e..850ef5b3e2c404c1ee583d4b99ed047a14f25928 100644 (file)
@@ -178,12 +178,13 @@ Player :: struct {
         immediate_set_color(color);
 
         rect := this->get_rect();
-        immediate_image(^player_texture, rect.x, rect.y, rect.w, rect.h);
+        immediate_image(^player_assets.texture, rect.x, rect.y, rect.w, rect.h);
     }
 }
 
-player_texture: Texture;
-
+player_assets: struct {
+    ["assets/images/player.png"] texture: Texture;
+}
 
 
 Wall :: struct {
index 54c0b3efedf074cd319492ced0a124a355c1eec6..810604dc81f1bb26f2bdf1acb152cc2baee2fb58 100644 (file)
@@ -136,30 +136,6 @@ entity_manager_load_from_file :: (use this: ^Entity_Manager, filename: str) {
     }
 
     if current_entity != null do this->add(current_entity);
-
-    get_any_for_member :: (base: any, member_name: str) -> any {
-        use type_info;
-
-        name := member_name;
-        info := cast(^Type_Info_Struct) get_type_info(base.type);
-        assert(info.kind == .Struct, "bad type");
-
-        part_name := string.read_until(^name, #char ".");
-        string.advance(^name, 1);
-
-        for info.members {
-            if it.name == part_name {
-                member_info := get_type_info(it.type);
-                if member_info.kind == .Struct {
-                    return get_any_for_member(any.{cast(^u8) base.data + it.offset, it.type}, name);
-                } else {
-                    return any.{cast(^u8) base.data + it.offset, it.type};
-                }
-            }
-        }
-
-        return .{null, void};
-    }
 }
 
 
index 5f6c8720769548668917517bec93b7b4814f0a19..36e28a50b20667477602184542c2d61554755abc 100644 (file)
@@ -7,17 +7,28 @@ use package glfw3
 //
 
 scene: Entity_Manager;
+item_store: Item_Store;
 
 game_init :: () {
-    player_texture = texture_make(#cstr "./assets/images/player.png");
+    // player_texture = texture_make(#cstr "./assets/images/player.png");
+
+    // This process of queueing the asset bucket should
+    // be made automatic somehow...
+    queue_assets(^player_assets);
+
+
+    load_assets();
 
     scene = entity_manager_create();
     scene->register(Player);
     scene->register(Wall);
     scene->register(Door);
-    scene->register(Item);
+    scene->register(Item_Entity);
     scene->load_from_file("scenes/quick_save.scene");
 
+    item_store = item_store_make();
+    item_store->load_items_from_file("scenes/default.items");
+
     #if DEBUG {
         println("Registered Entity types:");
         for scene.entity_types.entries {
index 5d51168214d543ba9c8f29f1d0d38ef1e32e8508..b5c14279d2710133c05aa5f5d8cf536d8194d8ad 100644 (file)
@@ -1,19 +1,36 @@
 
 use package core
+use package core.intrinsics.onyx { __zero_value as Zero }
 use package opengles
 use package stb_image
 
+#local texture_cache: Map(str, Texture);
+
 Texture :: struct {
     texture: GLint;
     width, height, channels: i32;
     filename: str;
 }
 
-texture_make :: (path: cstr) -> Texture {
+texture_make :: #match {}
+#match texture_make (filename: str) -> (Texture, bool) {
+    buffer: [512] u8;
+    memory.copy(~~ buffer, filename.data, math.min(filename.count, 511));
+    return texture_make(cast(cstr) buffer);
+}
+
+#match texture_make (path: cstr) -> (Texture, bool) {
+    filename := string.from_cstr(path);
+    if texture_cache->has(filename) {
+        return texture_cache[filename], true;
+    }
+
     tex: Texture;
-    tex.filename = path |> string.from_cstr();
+    tex.filename = filename;
     pixels := stbi_load(path, ^tex.width, ^tex.height, ^tex.channels, 4);
-    assert(pixels != null, "Failed to load texture.");
+    if pixels == null {
+        return Zero(Texture), false;
+    }
     defer stbi_image_free(pixels);
 
     glGenTextures(1, ^tex.texture);
@@ -28,11 +45,17 @@ texture_make :: (path: cstr) -> Texture {
 
     glBindTexture(GL_TEXTURE_2D, 0);
 
-    return tex;
+    // This assumes that the filename data is going to be persistant forever.
+    // Not a great assumption to make but is it really worth copying it?
+    texture_cache[filename] = tex;
+    return tex, true;
+}
+
+texture_free :: (use tex: ^Texture) {
+    glDeleteTextures(1, ^texture);
 }
 
 texture_use :: (use tex: ^Texture, texture_binding := 0) {
     glActiveTexture(GL_TEXTURE0 + texture_binding);
     glBindTexture(GL_TEXTURE_2D, texture);
 }
-
diff --git a/src/utils/any_utils.onyx b/src/utils/any_utils.onyx
new file mode 100644 (file)
index 0000000..46d1b17
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// The contents of this file will probably be merged with the
+// core libraries in Onyx at some point. I just haven't flushed
+// out the details yet on what everything should exactly do and
+// be responsible for.
+//
+
+use package core
+
+ptr_to_any :: (x: ^$T) -> any {
+    return .{x, T};
+}
+
+//
+// This function looks up a member's offset and type (effectively
+// an 'any'), given the base pointer and type in the form of an
+// 'any' and the member_name, which is a '.' separate list of
+// symbols.
+//
+get_any_for_member :: (base: any, member_name: str) -> any {
+    use type_info;
+
+    name := member_name;
+    info := cast(^Type_Info_Struct) get_type_info(base.type);
+    assert(info.kind == .Struct, "bad type");
+
+    part_name := string.read_until(^name, #char ".");
+    string.advance(^name, 1);
+
+    for info.members {
+        if it.name == part_name {
+            member_info := get_type_info(it.type);
+            if member_info.kind == .Struct {
+                return get_any_for_member(any.{cast(^u8) base.data + it.offset, it.type}, name);
+            } else {
+                return any.{cast(^u8) base.data + it.offset, it.type};
+            }
+        }
+    }
+
+    return .{null, void};
+}
diff --git a/src/utils/asset_loader.onyx b/src/utils/asset_loader.onyx
new file mode 100644 (file)
index 0000000..15a0b17
--- /dev/null
@@ -0,0 +1,61 @@
+
+use package core
+
+queue_assets :: (store: ^$T, callsite := #callsite) {
+    assets_to_load << .{ T, store, callsite };
+}
+
+load_assets :: () {
+    for^ assets_to_load {
+        load_asset_bucket(it);
+    }
+
+    array.clear(^assets_to_load);
+}
+
+
+#local {
+    assets_to_load: [..] Asset_Bucket_To_Load;
+
+    Asset_Bucket_To_Load :: struct {
+        type: type_expr;
+        dest: rawptr;
+
+        location: CallSite;
+    }
+
+    load_asset_bucket :: (bucket: ^Asset_Bucket_To_Load) {
+        use type_info;
+
+        struct_info := cast(^Type_Info_Struct) get_type_info(bucket.type);
+        if struct_info.kind != .Struct do return;
+
+        for struct_info.members {
+            load_asset(cast(^u8) bucket.dest + it.offset, it.type, bucket.location, it.tags);
+        }
+    }
+
+    load_asset :: (dest: rawptr, type: type_expr, location: CallSite, tags: [] any) {
+        switch type {
+            case Texture {
+                out_texture := cast(^Texture) dest;
+                path_tag := array.first(tags, (x) => x.type == str);
+
+                if path_tag != null {
+                    path := *cast(^str) path_tag.data;
+                    if texture, success := texture_make(path); success {
+                        *out_texture = texture;
+                    } else {
+                        printf("[ERROR] Failed to load texture '{}' for asset queued here: {}:{},{}.\n", path, location.file, location.line, location.column);
+                    }
+                } else {
+                    printf("[ERROR] Texture path not found for texture asset load here: {}:{},{}.\n", location.file, location.line, location.column);
+                }
+            }
+
+            case #default {
+                printf("[WARN]  Asset loader does not know how to load a '{}'.\n", type);
+            }
+        }
+    }
+}