From: Brendan Hansen Date: Wed, 2 Feb 2022 04:28:56 +0000 (-0600) Subject: dynamic entity creation; better font rendering X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=24e53bbb98602629ab006304e89ff70c45c353fe;p=bar-game.git dynamic entity creation; better font rendering --- diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index 9fdae6f..19ea6b4 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -11,6 +11,9 @@ use package core use package opengles use package glfw3 +Editor_Range :: struct {min, max: f32;} +Editor_Disabled :: struct {} + editor_init :: () { editor_font = font_lookup(.{"./assets/fonts/calibri.ttf", 18}); editor_big_font = font_lookup(.{"./assets/fonts/calibri.ttf", 24}); @@ -29,7 +32,10 @@ editor_update :: (dt: f32) { move_towards(^editor_openness, editor_target_openness, dt * 6); handle_clicking_tab(dt); - handle_entity_selction_and_dragging(dt); + switch active_tab { + case .Create do handle_placing_entities(); + case .Edit do handle_entity_selction_and_dragging(dt); + } } #local handle_clicking_tab :: (dt: f32) { @@ -39,11 +45,26 @@ editor_update :: (dt: f32) { clicked_tab = .None; } +#local handle_placing_entities :: () { + if active_index < 0 do return; + + if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) { + entity_type := ^scene.entity_types.entries[active_index].value; + printf("ADDING {}\n", entity_type); + + pos := mouse_get_position_vector(); + entity := entity_type.make(^scene); // scene->make(entity_type); + entity.pos = pos; + } +} + #local handle_entity_selction_and_dragging :: (dt: f32) { mouse_pos := mouse_get_position_vector(); if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) && mouse_pos.x < ~~window_width - sidebar_width && mouse_pos.y > menubar_height { + if active_tab == .Edit do active_index = -1; selected_entity_id = Entity_Nothing; + for scene.entities { get_rect := scene.entity_types[it.type].get_rect; if get_rect == null_proc do continue; @@ -89,8 +110,6 @@ editor_draw :: () { immediate_rectangle(r.x, r.y, r.w, r.h); } - background_color :: Color.{0.5, 0.5, 0.5, 0.7}; - { // Draw menu bar x := 0.0f; w := cast(f32) window_width; @@ -105,7 +124,7 @@ editor_draw :: () { h -= 4; w = 100; - for type_info.enum_values(Tabs) { + for^ type_info.enum_values(Tabs) { // Don't draw the "None" item; if it.value == 0 do continue; @@ -144,7 +163,7 @@ editor_draw :: () { switch active_tab { case .Create { - + render_create_sidebar(x, y, w, h); } case .Edit { @@ -157,6 +176,33 @@ editor_draw :: () { } } +#local render_create_sidebar :: (x, y, w, h: f32) { + i := 0; + for scene.entity_types.entries { + defer i += 1; + + type := it.key; + info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(type); + + if active_index == i { + immediate_set_color(.{.5,.5,.3}); + } elseif Rect.contains(.{x, y, w, 36.0f}, mouse_get_position_vector()) { + immediate_set_color(.{.4,.4,.4}); + + if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) { + active_index = i; + } + } else { + immediate_set_color(.{.3,.3,.3}); + } + + immediate_rectangle(x, y, w, 36.0f); + + y += 40.0f; + font_draw_centered(editor_font, x + 4, y - 18.0f, w, info.name); + } +} + #local render_entity_fields :: (entity: ^Entity, x, y, w, h: f32) { assert(entity != null, "entity is null"); assert(type_info.struct_inherits(entity.type, Entity), "entity is not an entity"); @@ -164,26 +210,38 @@ editor_draw :: () { font_print(editor_big_font, x + 2, y + 24, info.name); - render_struct_fields(any.{~~entity, entity.type}, 1, x, y + 4, w, h); + render_struct_fields(any.{~~entity, entity.type}, 0, x, y + 4, w, h); } #local render_struct_fields :: (v: any, i: i32, x, y, w, h: f32, depth := 0) -> (new_y: f32, new_i: i32) { Field_Height :: 22.0f info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(v.type); - for info.members { + for^ info.members { i += 1; y += Field_Height; - if i % 2 == 0 { + member_any := any.{cast(^u8) v.data + it.offset, it.type}; + + if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) { + if Rect.contains(.{x, y + 2, w, Field_Height + 2}, mouse_get_position_vector()) { + active_index = i - 1; + } + } + + if active_index + 1 == i { + immediate_set_color(.{.4,.4,.2}); + immediate_rectangle(x, y + 2, w, Field_Height + 2); + + render_field_editor(member_any, y, it.name); + + } elseif i % 2 == 0 { immediate_set_color(.{.3,.3,.3}); immediate_rectangle(x, y + 2, w, Field_Height + 2); } font_print(editor_font, x + 2, y + Field_Height, it.name); - member_any := any.{cast(^u8) v.data + it.offset, it.type}; - #persist depth_colors := Color.[ Color.{0.4, 0.2, 0.2}, Color.{0.2, 0.4, 0.2}, @@ -213,7 +271,38 @@ editor_draw :: () { return y, i; } +#local render_field_editor :: (v: any, y: f32, field_name: str) { + w := sidebar_width; + h := 200.0f; + x := ~~ window_width - sidebar_width * 2; + y = math.min(y, ~~ window_height - h); + immediate_set_color(.{.3,.3,.3}); + immediate_rectangle(x, y, w, h); + + y += 32; + font_print(editor_font, x, y, field_name); + + switch v.type { + type_is(i32) { + font_print(editor_font, x, y + 32, "INT: {}\n", value); + } + + type_is(f32) { + font_print(editor_font, x, y + 32, "FLOAT: {}\n", value); + } + } + + type_is :: macro (T: type_expr, body: Code) { + case T { + value := *cast(^T) v.data; + #insert body; + } + } +} + #local { + background_color :: Color.{0.5, 0.5, 0.5, 0.7}; + editor_font: Font; editor_big_font: Font; @@ -234,4 +323,6 @@ editor_draw :: () { active_tab := Tabs.Create; clicked_tab := Tabs.None; + + active_index := -1; } diff --git a/src/entity/manager.onyx b/src/entity/manager.onyx index 30aa7e9..68119d5 100644 --- a/src/entity/manager.onyx +++ b/src/entity/manager.onyx @@ -30,7 +30,9 @@ IsEntity :: interface (e: $E) { e.init(e, e.init_data.{}); // This constraint ensures that everything in the initialization data is given a default value. } -Entity_Handles :: struct { +Entity_Info :: struct { + make : (scene: ^Entity_Manager) -> ^Entity = null_proc; + update : (entity: ^Entity, dt: f32) -> void = null_proc; draw : (entity: ^Entity) -> void = null_proc; get_rect : (entity: ^Entity) -> Rect = null_proc; @@ -44,13 +46,14 @@ Entity_Manager :: struct { entities: [..] ^Entity; entity_map: Map(Entity_ID, ^Entity); - entity_types: Map(type_expr, Entity_Handles); + entity_types: Map(type_expr, Entity_Info); next_entity_id: Entity_ID; register :: entity_manager_register; add :: entity_manager_add; make :: entity_manager_make; + make_old :: entity_manager_make_old; update :: entity_manager_update; draw :: entity_manager_draw; get :: entity_manager_get; @@ -95,17 +98,18 @@ entity_manager_register :: (use this: ^Entity_Manager, $entity_type: type_expr) } - handles := Entity_Handles.{}; + info := Entity_Info.{}; + info.make = #solidify entity_manager_make { entity_type=entity_type }; @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.update) { handles.update = entity_type.update; if DEBUG do printf("{} has '{}'.\n", entity_type, "update"); } - #if #defined(entity_type.draw) { handles.draw = entity_type.draw; if DEBUG do printf("{} has '{}'.\n", entity_type, "draw"); } - #if #defined(entity_type.get_rect) { handles.get_rect = entity_type.get_rect; if DEBUG do printf("{} has '{}'.\n", entity_type, "get_rect"); } - #if #defined(entity_type.interact) { handles.interact = entity_type.interact; if DEBUG do printf("{} has '{}'.\n", entity_type, "interact"); } + #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"); } + #if #defined(entity_type.interact) { info.interact = entity_type.interact; if DEBUG do printf("{} has '{}'.\n", entity_type, "interact"); } - entity_types[entity_type] = handles; + entity_types[entity_type] = info; } } @@ -121,7 +125,14 @@ entity_manager_add :: (use this: ^Entity_Manager, entity: ^$T) -> Entity_ID wher return entity.id; } -entity_manager_make :: (use this: ^Entity_Manager, $entity_type: type_expr, data: entity_type.init_data = .{}) -> ^entity_type where IsEntity(^entity_type) { +entity_manager_make :: (use this: ^Entity_Manager, $entity_type: type_expr) -> ^entity_type where IsEntity(^entity_type) { + entity := new(entity_type, allocator=entity_allocator); + entity_type.init(entity, entity_type.init_data.{}); + this->add(entity); + return entity; +} + +entity_manager_make_old :: (use this: ^Entity_Manager, $entity_type: type_expr, data: entity_type.init_data = .{}) -> ^entity_type where IsEntity(^entity_type) { entity := new(entity_type, allocator=entity_allocator); entity_type.init(entity, data); this->add(entity); diff --git a/src/entity/player.onyx b/src/entity/player.onyx index b1c6a36..736b4b8 100644 --- a/src/entity/player.onyx +++ b/src/entity/player.onyx @@ -201,7 +201,7 @@ Door :: struct { init_data :: struct { pos := Vector2.{0, 0}; - size := Vector2.{0, 0}; + size := Vector2.{10, 10}; } init :: (use this: ^Door, data: init_data) { diff --git a/src/gfx/font.onyx b/src/gfx/font.onyx index 06599da..3e32076 100644 --- a/src/gfx/font.onyx +++ b/src/gfx/font.onyx @@ -66,6 +66,7 @@ Font :: struct { texture: GLint; texture_width, texture_height: i32; chars: [] stbtt_packedchar; + em: f32; } font_make :: (fd: FontDescriptor) -> Font { @@ -102,7 +103,8 @@ font_make :: (fd: FontDescriptor) -> Font { texture = texture, texture_width = texture_size, texture_height = texture_size, - chars = char_data + chars = char_data, + em = ~~fd.size, }; font_registry[fd] = font; @@ -121,27 +123,59 @@ font_print :: (font: Font, x, y: f32, format: str, va: ..any) { } font_draw :: (font: Font, x, y: f32, msg: str) { - // If this is being used in conjunction with the immediate - // rendering system, make sure the immediate objects are flushed - // before trying to render over them. - #if #defined(immediate_flush) { - immediate_flush(); + quads: ^stbtt_aligned_quad = alloc.from_stack(msg.count * sizeof stbtt_aligned_quad); + quad_num := 0; + + x_, y_ := x, y; + + for msg { + if it == #char "\n" { + x_ = x; + y_ += font.em + 2; + } + + stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, + ~~(it - #char " "), ^x_, ^y_, ^quads[quad_num], false); + + quad_num += 1; } + font_render(font, quads[0 .. quad_num]); +} + +font_draw_centered :: (font: Font, x, y, max_width: f32, msg: str) { quads: ^stbtt_aligned_quad = alloc.from_stack(msg.count * sizeof stbtt_aligned_quad); quad_num := 0; + width := font_get_width(font, msg); x_, y_ := x, y; + x_ = (max_width - width) / 2 + x; for msg { + if it == #char "\n" { + x_ = (max_width - width) / 2 + x; + y_ += font.em + 2; + } + stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, ~~(it - #char " "), ^x_, ^y_, ^quads[quad_num], false); quad_num += 1; } + font_render(font, quads[0 .. quad_num]); +} + +#local font_render :: (font: Font, quads: [] stbtt_aligned_quad) { + // If this is being used in conjunction with the immediate + // rendering system, make sure the immediate objects are flushed + // before trying to render over them. + #if #defined(immediate_flush) { + immediate_flush(); + } + glBindBuffer(GL_ARRAY_BUFFER, font_vbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, quad_num * sizeof stbtt_aligned_quad, quads); + glBufferSubData(GL_ARRAY_BUFFER, 0, quads.count * sizeof stbtt_aligned_quad, quads.data); glBindBuffer(GL_ARRAY_BUFFER, -1); glActiveTexture(GL_TEXTURE0); @@ -152,21 +186,29 @@ font_draw :: (font: Font, x, y: f32, msg: str) { glDisable(GL_DEPTH_TEST); glBindVertexArray(font_vao); - glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, ~~0, quad_num); + glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, ~~0, quads.count); glBindTexture(GL_TEXTURE_2D, -1); glBindVertexArray(-1); } font_get_width :: (font: Font, msg: str) -> f32 { x_, y_ := 0.0f, 0.0f; + width := 0.0f; quad: stbtt_aligned_quad; for msg { + if it == #char "\n" { + width = math.max(width, x_); + x_ = 0; + y_ += font.em + 2; + continue; + } + stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, ~~(it - #char " "), ^x_, ^y_, ^quad, false); } - return x_; + return math.max(x_, width); } diff --git a/src/main.onyx b/src/main.onyx index 8c40123..28656ea 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -45,22 +45,22 @@ init :: () { #if DEBUG { debug_font = font_lookup(.{"./assets/fonts/calibri.ttf", 16}); } scene = entity_manager_create(); - scene->make(Player, .{ pos = .{300, 300}, controls=player_1_controls }); - scene->make(Player, .{ pos = .{400, 300}, controls=player_2_controls, color=.{1,0,0} }); - - scene->make(Wall, .{ .{100, 100}, .{400, 50} }); - // scene->make(Wall, .{ .{100, 100}, .{50, 400} }); - // scene->make(Wall, .{ .{450, 100}, .{50, 400} }); - // scene->make(Wall, .{ .{100, 450}, .{400, 50} }); - - scene->make(Door, .{ .{150, 150}, .{50, 50} }); - scene->make(Door, .{ .{400, 150}, .{50, 50} }); - scene->make(Door, .{ .{400, 400}, .{50, 50} }); - scene->make(Door, .{ .{150, 400}, .{50, 50} }); - - scene->make(Item, .{ pos=.{ 250, 250 }, color=.{1,0,0} }); - scene->make(Item, .{ pos=.{ 275, 250 }, color=.{0,1,0} }); - scene->make(Item, .{ pos=.{ 300, 250 }, color=.{0,0,1} }); + scene->make_old(Player, .{ pos = .{300, 300}, controls=player_1_controls }); + scene->make_old(Player, .{ pos = .{400, 300}, controls=player_2_controls, color=.{1,0,0} }); + + scene->make_old(Wall, .{ .{100, 100}, .{400, 50} }); + // scene->make_old(Wall, .{ .{100, 100}, .{50, 400} }); + // scene->make_old(Wall, .{ .{450, 100}, .{50, 400} }); + // scene->make_old(Wall, .{ .{100, 450}, .{400, 50} }); + + scene->make_old(Door, .{ .{150, 150}, .{50, 50} }); + scene->make_old(Door, .{ .{400, 150}, .{50, 50} }); + scene->make_old(Door, .{ .{400, 400}, .{50, 50} }); + scene->make_old(Door, .{ .{150, 400}, .{50, 50} }); + + scene->make_old(Item, .{ pos=.{ 250, 250 }, color=.{1,0,0} }); + scene->make_old(Item, .{ pos=.{ 275, 250 }, color=.{0,1,0} }); + scene->make_old(Item, .{ pos=.{ 300, 250 }, color=.{0,0,1} }); #if DEBUG { println("Registered Entity types:");