diff --git a/Makefile b/Makefile index 1ebed03..3f9bd52 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,25 @@ build-shaders: ./sokol-shdc -i shaders/src/cube.glsl -o shaders/out/cube.odin -l metal_macos -f sokol_odin ./sokol-shdc -i shaders/src/outline.glsl -o shaders/out/outline.odin -l metal_macos -f sokol_odin + build: build-shaders odin build . -use-single-module build-debug: build-shaders odin build . -debug -use-single-module +build-release: build-shaders + odin build . -o:speed -use-single-module + run: build-shaders odin run . -use-single-module run-debug: build-shaders odin run . -debug -use-single-module +run-release: build-shaders + odin run . -o:speed -use-single-module + check: build-shaders odin strip-semicolon . odin check . diff --git a/ecs/camera_system.odin b/ecs/camera_system.odin index c484ec1..e6dc7e2 100644 --- a/ecs/camera_system.odin +++ b/ecs/camera_system.odin @@ -4,18 +4,13 @@ import "core:math" import "core:math/linalg" CameraSystem :: struct { - using base: SystemBase, -} - - -camera_system_init :: proc(camera_system: ^CameraSystem) { - + using _: SystemBase, } camera_system_update :: proc(camera_system: ^CameraSystem, coordinator: ^Coordinator, dt: f32) { - for entity in camera_system.entities { - camera := coordinator_get_component(CameraComponent, coordinator, entity) - input := coordinator_get_component(InputComponent, coordinator, entity) + for entity_id in camera_system.entities { + camera := coordinator_get_component(coordinator, CameraComponent, entity_id) + input := coordinator_get_component(coordinator, InputComponent, entity_id) move_input: Vec3 if input.key_down[.W] do move_input.y = 1 diff --git a/ecs/component_manager.odin b/ecs/component_manager.odin index 3eb8e0f..5cc6f10 100644 --- a/ecs/component_manager.odin +++ b/ecs/component_manager.odin @@ -1,76 +1,88 @@ +#+private package ecs import "core:log" ComponentManager :: struct { - component_types: map[typeid]ComponentType, + component_ids: map[typeid]ComponentID, component_pools: map[typeid]^ComponentPool(any), - destroy_procs: map[typeid]proc(pool: ^ComponentPool(any), entity_id: EntityID), - next_component_type: ComponentType, + next_component_id: ComponentID, + + component_pool_destroy_entity_cbs: map[typeid]proc(pool: ^ComponentPool(any), entity_id: EntityID), + component_pool_delete_cbs: map[typeid]proc(pool: ^ComponentPool(any)), } -component_manager_create :: proc() -> ComponentManager { - component_manager := ComponentManager { - component_types = make(map[typeid]ComponentType, context.allocator), - component_pools = make(map[typeid]^ComponentPool(any), context.allocator), - next_component_type = 0 - } +component_manager_init :: proc(component_manager: ^ComponentManager) { + component_manager.component_ids = make(map[typeid]ComponentID, context.allocator) + component_manager.component_pools = make(map[typeid]^ComponentPool(any), context.allocator) - return component_manager + component_manager.component_pool_destroy_entity_cbs = make(map[typeid]proc(pool: ^ComponentPool(any), entity_id: EntityID), context.allocator) + component_manager.component_pool_delete_cbs = make(map[typeid]proc(pool: ^ComponentPool(any)), context.allocator) + + component_manager.next_component_id = 0 } -component_manager_register_component :: proc($T: typeid, component_manager: ^ComponentManager) { - log.assertf(T not_in component_manager.component_types, "Registering component more than once") +component_manager_register_component :: proc($Component: typeid, component_manager: ^ComponentManager) { + log.assertf(Component not_in component_manager.component_ids, "Registering component more than once") - component_manager.component_types[T] = component_manager.next_component_type - component_pool := new(ComponentPool(T), context.allocator) - component_pool^ = component_pool_create(T) - component_manager.component_pools[T] = cast(^ComponentPool(any))component_pool + component_manager.component_ids[Component] = component_manager.next_component_id - component_manager.destroy_procs[T] = proc(component_pool: ^ComponentPool(any), id: EntityID) { - typed_component_pool := cast(^ComponentPool(T))component_pool + component_pool := new(ComponentPool(Component), context.allocator) + component_pool_init(component_pool) - if id in typed_component_pool.entity_to_index { - component_pool_remove_data(typed_component_pool, id) + component_manager.component_pools[Component] = cast(^ComponentPool(any))component_pool + + component_manager.component_pool_destroy_entity_cbs[Component] = proc(any_component_pool: ^ComponentPool(any), entity_id: EntityID) { + typed_component_pool := cast(^ComponentPool(Component))any_component_pool + if entity_id in typed_component_pool.entity_to_index { + component_pool_remove_data(typed_component_pool, entity_id) } } - component_manager.next_component_type += 1 + component_manager.component_pool_delete_cbs[Component] = proc(any_component_pool: ^ComponentPool(any)) { + typed_component_pool := cast(^ComponentPool(Component))any_component_pool + component_pool_delete(typed_component_pool) + free(typed_component_pool) + } + + component_manager.next_component_id += 1 } -component_manager_get_component_type :: proc($T: typeid, component_manager: ^ComponentManager) -> ComponentType { - log.assertf(T in component_manager.component_types, "Component not registered before use") - return component_manager.component_types[T] +component_manager_get_component_id :: proc(component_manager: ^ComponentManager, $Component: typeid) -> ComponentID { + log.assertf(Component in component_manager.component_ids, "Component not registered before use") + return component_manager.component_ids[Component] } -component_manager_add_component :: proc($T: typeid, component_manager: ^ComponentManager, entity_id: EntityID, component: T) { - component_pool := cast(^ComponentPool(T))component_manager.component_pools[T] +component_manager_add_component :: proc(component_manager: ^ComponentManager, component: $Component, entity_id: EntityID) { + component_pool := cast(^ComponentPool(Component))component_manager.component_pools[Component] component_pool_insert_data(component_pool, entity_id, component) } -component_manager_remove_component :: proc($T: typeid, component_manager: ^ComponentManager, entity_id: EntityID) { - component_pool := cast(^ComponentPool(T))component_manager.component_pools[T] +component_manager_remove_component :: proc(component_manager: ^ComponentManager, $Component: typeid, entity_id: EntityID) { + component_pool := cast(^ComponentPool(Component))component_manager.component_pools[Component] component_pool_remove_data(component_pool, entity_id) } -component_manager_get_component :: proc($T: typeid, component_manager: ^ComponentManager, entity_id: EntityID) -> ^T { - component_pool := cast(^ComponentPool(T)) component_manager.component_pools[T] +component_manager_get_component :: proc(component_manager: ^ComponentManager, $Component: typeid, entity_id: EntityID) -> ^Component { + component_pool := cast(^ComponentPool(Component)) component_manager.component_pools[Component] return component_pool_get(component_pool, entity_id) } component_manager_destroy_entity :: proc(component_manager: ^ComponentManager, entity_id: EntityID) { - for T, component_pool in component_manager.component_pools { - component_manager.destroy_procs[T](component_pool, entity_id) + for Component, component_pool in component_manager.component_pools { + component_manager.component_pool_destroy_entity_cbs[Component](component_pool, entity_id) } } -component_manager_destroy :: proc(component_manager: ^ComponentManager) { - for _, &component_pool in component_manager.component_pools { - component_pool_destroy(component_pool) - free(component_pool) +component_manager_delete :: proc(component_manager: ^ComponentManager) { + for Component, &component_pool in component_manager.component_pools { + component_manager.component_pool_delete_cbs[Component](component_pool) } delete(component_manager.component_pools) - delete(component_manager.component_types) + delete(component_manager.component_ids) + + delete(component_manager.component_pool_destroy_entity_cbs) + delete(component_manager.component_pool_delete_cbs) } diff --git a/ecs/component_pool.odin b/ecs/component_pool.odin index dc96a8a..4dbf576 100644 --- a/ecs/component_pool.odin +++ b/ecs/component_pool.odin @@ -1,26 +1,23 @@ +#+private package ecs import "core:log" -ComponentPool :: struct(T: typeid) { - data: []T, +ComponentPool :: struct(Component: typeid) { + data: []Component, entity_to_index: map[EntityID]uintptr, index_to_entity: map[uintptr]EntityID, size: uintptr, } -component_pool_create :: proc($T: typeid) -> ComponentPool(T) { - component_pool := ComponentPool(T) { - data = make([]T, ENTITY_MAX), - entity_to_index = make(map[EntityID]uintptr, context.allocator), - index_to_entity = make(map[uintptr]EntityID, context.allocator), - size = 0, - } - - return component_pool +component_pool_init :: proc(component_pool: ^ComponentPool($Component)) { + component_pool.data = make([]Component, ENTITY_MAX, context.allocator) + component_pool.entity_to_index = make(map[EntityID]uintptr, context.allocator) + component_pool.index_to_entity = make(map[uintptr]EntityID, context.allocator) + component_pool.size = 0 } -component_pool_insert_data :: proc(component_pool: ^ComponentPool($T), entity_id: EntityID, component: T) { +component_pool_insert_data :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID, component: Component) { log.assertf(entity_id not_in component_pool.entity_to_index, "Component already added to entity") new_idx := component_pool.size @@ -31,7 +28,7 @@ component_pool_insert_data :: proc(component_pool: ^ComponentPool($T), entity_id component_pool.size += 1 } -component_pool_remove_data :: proc(component_pool: ^ComponentPool($T), entity_id: EntityID) { +component_pool_remove_data :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID) { log.assertf(entity_id in component_pool.entity_to_index, "Entity doesn't have component") removed_entity_idx := component_pool.entity_to_index[entity_id] @@ -48,21 +45,21 @@ component_pool_remove_data :: proc(component_pool: ^ComponentPool($T), entity_id component_pool.size -= 1 } -component_pool_get :: proc(component_pool: ^ComponentPool($T), entity_id: EntityID) -> ^T { +component_pool_get :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID) -> ^Component { log.assertf(entity_id in component_pool.entity_to_index, "Entity doesn't have component") idx := component_pool.entity_to_index[entity_id] return &component_pool.data[idx] } -component_pool_destroy_entity :: proc(component_pool: ^ComponentPool($T), entity_id: EntityID) { +component_pool_destroy_entity :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID) { if entity_id in component_pool.entity_to_index { component_pool_remove_data(component_pool, entity_id) } } -component_pool_destroy :: proc(component_pool: ^ComponentPool($T)) { +component_pool_delete :: proc(component_pool: ^ComponentPool($Component)) { + delete(component_pool.data) delete(component_pool.entity_to_index) delete(component_pool.index_to_entity) - delete(component_pool.data) } diff --git a/ecs/constants.odin b/ecs/constants.odin index 95380d6..5a5c4b8 100644 --- a/ecs/constants.odin +++ b/ecs/constants.odin @@ -6,4 +6,4 @@ COMPONENT_MAX :: 32 ID :: u32 EntityID :: ID -ComponentType :: u16 +ComponentID :: u16 diff --git a/ecs/coordinator.odin b/ecs/coordinator.odin index 81feded..27f8636 100644 --- a/ecs/coordinator.odin +++ b/ecs/coordinator.odin @@ -1,82 +1,70 @@ package ecs Coordinator :: struct { - component_manager: ^ComponentManager, - entity_manager: ^EntityManager, - system_manager: ^SystemManager, + component_manager: ComponentManager, + entity_manager: EntityManager, + system_manager: SystemManager, } -coordinator_create :: proc() -> Coordinator { - coordinator := Coordinator{} - coordinator.component_manager = new(ComponentManager, context.allocator) - coordinator.component_manager^ = component_manager_create() - - coordinator.entity_manager = new(EntityManager, context.allocator) - coordinator.entity_manager^ = entity_manager_create() - - coordinator.system_manager = new(SystemManager, context.allocator) - coordinator.system_manager^ = system_manager_create() - - return coordinator +coordinator_init:: proc(coordinator: ^Coordinator) { + component_manager_init(&coordinator.component_manager) + entity_manager_init(&coordinator.entity_manager) + system_manager_init(&coordinator.system_manager) } coordinator_create_entity :: proc(coordinator: ^Coordinator) -> EntityID { - return entity_manager_create_entity(coordinator.entity_manager) + return entity_manager_create_entity(&coordinator.entity_manager) } coordinator_destroy_entity :: proc(coordinator: ^Coordinator, entity_id: EntityID) { - component_manager_destroy_entity(coordinator.component_manager, entity_id) - entity_manager_destroy_entity(coordinator.entity_manager, entity_id) - system_manager_destroy_entity(coordinator.system_manager, entity_id) + component_manager_destroy_entity(&coordinator.component_manager, entity_id) + entity_manager_destroy_entity(&coordinator.entity_manager, entity_id) + system_manager_destroy_entity(&coordinator.system_manager, entity_id) } -coordinator_register_component :: proc($T: typeid, coordinator: ^Coordinator) { - component_manager_register_component(T, coordinator.component_manager) +coordinator_register_component :: proc(coordinator: ^Coordinator, $Component: typeid) { + component_manager_register_component(Component, &coordinator.component_manager) } -coordinator_add_component :: proc($T: typeid, coordinator: ^Coordinator, entity_id: EntityID, component: T) { - component_manager_add_component(T, coordinator.component_manager, entity_id, component) +coordinator_add_component :: proc(coordinator: ^Coordinator, component: $Component, entity_id: EntityID) { + component_manager_add_component(&coordinator.component_manager, component, entity_id) - signature := entity_manager_get_signature(coordinator.entity_manager, entity_id) - signature_set(&signature, component_manager_get_component_type(T, coordinator.component_manager)) - entity_manager_set_signature(coordinator.entity_manager, entity_id, signature) + signature := entity_manager_get_signature(&coordinator.entity_manager, entity_id) + signature_set(&signature, component_manager_get_component_id(&coordinator.component_manager, Component)) + entity_manager_set_signature(&coordinator.entity_manager, entity_id, signature) - system_manager_change_entity_signature(coordinator.system_manager, entity_id, signature) + system_manager_change_entity_signature(&coordinator.system_manager, entity_id, signature) } -coordinator_remove_component :: proc($T: typeid, coordinator: ^Coordinator, entity_id: EntityID) { - component_manager_remove_component(T, coordinator.component_manager, entity_id) +coordinator_remove_component :: proc(coordinator: ^Coordinator, $Component: typeid, entity_id: EntityID) { + component_manager_remove_component(&coordinator.component_manager, Component, entity_id) - signature := entity_manager_get_signature(coordinator.entity_manager, entity_id) - signature_unset(&signature, component_manager_get_component_type(T, coordinator.component_manager)) - entity_manager_set_signature(coordinator.entity_manager, entity_id, signature) + signature := entity_manager_get_signature(&coordinator.entity_manager, entity_id) + signature_unset(&signature, component_manager_get_component_id(&coordinator.component_manager, Component)) + entity_manager_set_signature(&coordinator.entity_manager, entity_id, signature) - system_manager_change_entity_signature(coordinator.system_manager, entity_id, signature) + system_manager_change_entity_signature(&coordinator.system_manager, entity_id, signature) } -coordinator_get_component :: proc($T: typeid, coordinator: ^Coordinator, entity_id: EntityID) -> ^T { - return component_manager_get_component(T, coordinator.component_manager, entity_id) +coordinator_get_component :: proc(coordinator: ^Coordinator, $Component: typeid, entity_id: EntityID) -> ^Component { + return component_manager_get_component(&coordinator.component_manager, Component, entity_id) } -coordinator_get_component_type :: proc($T: typeid, coordinator: ^Coordinator) -> ComponentType { - return component_manager_get_component_type(T, coordinator.component_manager) +coordinator_get_component_id :: proc(coordinator: ^Coordinator, $Component: typeid) -> ComponentID { + return component_manager_get_component_id(&coordinator.component_manager, Component) } -coordinator_register_system :: proc($T: typeid, coordinator: ^Coordinator) -> ^T { - return system_manager_register_system(T, coordinator.system_manager) +coordinator_register_system :: proc(coordinator: ^Coordinator, $System: typeid) -> ^System { + return system_manager_register_system(&coordinator.system_manager, System) } -coordinator_set_system_signature :: proc($T: typeid, coordinator: ^Coordinator, signature: Signature) { - system_manager_set_signature(T, coordinator.system_manager, signature) +coordinator_set_system_signature :: proc(coordinator: ^Coordinator, $System: typeid, signature: Signature) { + system_manager_set_signature(&coordinator.system_manager, System, signature) } -coordinator_destroy :: proc(coordinator: ^Coordinator) { - component_manager_destroy(coordinator.component_manager) - entity_manager_destroy(coordinator.entity_manager) - system_manager_destroy(coordinator.system_manager) - - free(coordinator.component_manager) - free(coordinator.entity_manager) - free(coordinator.system_manager) +coordinator_delete :: proc(coordinator: ^Coordinator) { + component_manager_delete(&coordinator.component_manager) + entity_manager_delete(&coordinator.entity_manager) + system_manager_delete(&coordinator.system_manager) } diff --git a/ecs/entity_manager.odin b/ecs/entity_manager.odin index a670f9e..5ff342a 100644 --- a/ecs/entity_manager.odin +++ b/ecs/entity_manager.odin @@ -1,3 +1,4 @@ +#+private package ecs import "core:log" @@ -9,15 +10,12 @@ EntityManager :: struct { living_entity_count: u32, } -entity_manager_create :: proc() -> EntityManager { - entity_manager := EntityManager{living_entity_count = 0} +entity_manager_init :: proc(entity_manager: ^EntityManager) { queue.init(&entity_manager.available_entities) for entity_id in 0.. EntityID { @@ -49,6 +47,6 @@ entity_manager_get_signature :: proc(entity_manager: ^EntityManager, entity_id: return entity_manager.signatures[entity_id] } -entity_manager_destroy :: proc(entity_manager: ^EntityManager) { +entity_manager_delete :: proc(entity_manager: ^EntityManager) { queue.destroy(&entity_manager.available_entities) } diff --git a/ecs/input_system.odin b/ecs/input_system.odin index b09fc96..b36140d 100644 --- a/ecs/input_system.odin +++ b/ecs/input_system.odin @@ -3,12 +3,12 @@ package ecs import sa "../sokol/app" InputSystem :: struct { - using base: SystemBase, + using _: SystemBase, } input_system_update :: proc(input_system: ^InputSystem, coordinator: ^Coordinator, event: ^sa.Event) { - for entity in input_system.entities { - input := coordinator_get_component(InputComponent, coordinator, entity) + for entity_id in input_system.entities { + input := coordinator_get_component(coordinator, InputComponent, entity_id) #partial switch event.type { case .MOUSE_MOVE: @@ -24,9 +24,9 @@ input_system_update :: proc(input_system: ^InputSystem, coordinator: ^Coordinato } input_system_mouse_reset :: proc(input_system: ^InputSystem, coordinator: ^Coordinator) { - for entity in input_system.entities { - input := coordinator_get_component(InputComponent, coordinator, entity) + for entity_id in input_system.entities { + input_id := coordinator_get_component(coordinator, InputComponent, entity_id) - input.mouse_movement = { 0, 0 } + input_id.mouse_movement = { 0, 0 } } } diff --git a/ecs/physics_system.odin b/ecs/physics_system.odin index ab577b1..be5bad3 100644 --- a/ecs/physics_system.odin +++ b/ecs/physics_system.odin @@ -5,23 +5,23 @@ import "core:log" import program_config "../config" PhysicsSystem :: struct { - using base: SystemBase, + using _: SystemBase, } physics_system_update :: proc(physics_system: ^PhysicsSystem, coordinator: ^Coordinator, dt: f32) { entities_to_delete := make([dynamic]EntityID) defer delete(entities_to_delete) - for entity in physics_system.entities { - rigid_body := coordinator_get_component(RigidBodyComponent, coordinator, entity) - transform := coordinator_get_component(TransformComponent, coordinator, entity) - gravity := coordinator_get_component(GravityComponent, coordinator, entity) + for entity_id in physics_system.entities { + rigid_body := coordinator_get_component(coordinator, RigidBodyComponent, entity_id) + transform := coordinator_get_component(coordinator, TransformComponent, entity_id) + gravity := coordinator_get_component(coordinator, GravityComponent, entity_id) transform.position += rigid_body.velocity * dt rigid_body.velocity += gravity.force * dt if transform.position.y < program_config.Y_DESPAWN_CUTOFF { - append(&entities_to_delete, entity) + append(&entities_to_delete, entity_id) } } diff --git a/ecs/render_system.odin b/ecs/render_system.odin index 42c030d..3c2d1e5 100644 --- a/ecs/render_system.odin +++ b/ecs/render_system.odin @@ -43,14 +43,14 @@ Material :: struct { } RenderSystem :: struct { - using base: SystemBase, - camera_entity: EntityID, + using _: SystemBase, + user_entity: EntityID, materials: map[MaterialID]Material, meshes : map[MeshID]Mesh, } -@(private) +@(private="file") init_outline_material :: proc(render_system: ^RenderSystem) { shader := sg.make_shader(shaders.outline_shader_desc(sg.query_backend())) pipeline := sg.make_pipeline({ @@ -79,7 +79,7 @@ init_outline_material :: proc(render_system: ^RenderSystem) { } } -@(private) +@(private="file") init_cube_material :: proc(render_system: ^RenderSystem) { shader := sg.make_shader(shaders.cube_shader_desc(sg.query_backend())) pipeline := sg.make_pipeline({ @@ -108,7 +108,7 @@ init_cube_material :: proc(render_system: ^RenderSystem) { } } -@(private) +@(private="file") init_cube_mesh :: proc (render_system: ^RenderSystem) { cube_vertices := []CubeVertexData { { pos = { -0.5, -0.5, 0.5 } }, @@ -171,7 +171,7 @@ init_cube_mesh :: proc (render_system: ^RenderSystem) { } } -render_system_init :: proc(render_system: ^RenderSystem, camera_entity: EntityID) { +render_system_init :: proc(render_system: ^RenderSystem, user_entity: EntityID) { default_context := runtime.default_context() sg.setup({ @@ -182,7 +182,7 @@ render_system_init :: proc(render_system: ^RenderSystem, camera_entity: EntityID render_system.materials = make(map[MaterialID]Material) render_system.meshes = make(map[MeshID]Mesh) - render_system.camera_entity = camera_entity + render_system.user_entity = user_entity init_cube_mesh(render_system) init_cube_material(render_system) @@ -209,7 +209,7 @@ render_system_delete :: proc(render_system: ^RenderSystem, coordinator: ^Coordin sg.shutdown() } -@(private) +@(private="file") CLEAR_SCREEN_ACTION :: sg.Pass_Action{ colors = { 0 = { @@ -219,10 +219,11 @@ CLEAR_SCREEN_ACTION :: sg.Pass_Action{ } } +@(private="file") outline_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) { - for entity in render_system.entities { - transform := coordinator_get_component(TransformComponent, coordinator, entity) - mesh_id := coordinator_get_component(MeshComponent, coordinator, entity).mesh_id + for entity_id in render_system.entities { + transform := coordinator_get_component(coordinator, TransformComponent, entity_id) + mesh_id := coordinator_get_component(coordinator, MeshComponent, entity_id).mesh_id mesh := render_system.meshes[mesh_id] scale_mat := linalg.matrix4_scale_f32(transform.scale * 1.2) @@ -257,17 +258,18 @@ outline_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, pr } +@(private="file") cube_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) { - for entity in render_system.entities { - transform := coordinator_get_component(TransformComponent, coordinator, entity) + for entity_id in render_system.entities { + transform := coordinator_get_component(coordinator, TransformComponent, entity_id) - mesh_id := coordinator_get_component(MeshComponent, coordinator, entity).mesh_id + mesh_id := coordinator_get_component(coordinator, MeshComponent, entity_id).mesh_id mesh := render_system.meshes[mesh_id] - material_id := coordinator_get_component(MaterialComponent, coordinator, entity).material_id + material_id := coordinator_get_component(coordinator, MaterialComponent, entity_id).material_id material := render_system.materials[material_id] - color := coordinator_get_component(ColorComponent, coordinator, entity) + color := coordinator_get_component(coordinator, ColorComponent, entity_id) scale_mat := linalg.matrix4_scale_f32(transform.scale) rot_mat := linalg.matrix4_from_yaw_pitch_roll_f32( @@ -295,7 +297,7 @@ cube_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: } render_system_update :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator) { - camera := coordinator_get_component(CameraComponent, coordinator, render_system.camera_entity) + camera := coordinator_get_component(coordinator, CameraComponent, render_system.user_entity) proj := linalg.matrix4_perspective_f32(70, sa.widthf() / sa.heightf(), 0.001, 1000) view := linalg.matrix4_look_at_f32(camera.position, camera.target, { 0, 1, 0 } ) @@ -308,11 +310,13 @@ render_system_update :: proc(render_system: ^RenderSystem, coordinator: ^Coordin sg.commit() } +@(private="file") sg_range :: proc { sg_range_from_slice, sg_range_from_struct, } +@(private="file") sg_range_from_slice :: proc(s: []$T) -> sg.Range { return { ptr = raw_data(s), @@ -320,6 +324,7 @@ sg_range_from_slice :: proc(s: []$T) -> sg.Range { } } +@(private="file") sg_range_from_struct :: proc(s: ^$T) -> sg.Range where intrinsics.type_is_struct(T) { return { ptr = s, diff --git a/ecs/signature.odin b/ecs/signature.odin index 6d8c0a9..5c8b2f4 100644 --- a/ecs/signature.odin +++ b/ecs/signature.odin @@ -2,15 +2,15 @@ package ecs Signature :: bit_set[0.. Signature { +signature_make :: proc() -> Signature { return Signature{} } -signature_set :: proc(signature: ^Signature, type: ComponentType) { +signature_set :: proc(signature: ^Signature, type: ComponentID) { signature^ += {cast(int)type} } -signature_unset :: proc(signature: ^Signature, type: ComponentType) { +signature_unset :: proc(signature: ^Signature, type: ComponentID) { signature^ -= {cast(int)type} } diff --git a/ecs/system_manager.odin b/ecs/system_manager.odin index 4b04612..7a42f65 100644 --- a/ecs/system_manager.odin +++ b/ecs/system_manager.odin @@ -1,10 +1,14 @@ -package ecs +#+private +package ecs import "base:intrinsics" import "core:log" +@(private = "file") +EntitySet :: map[EntityID]struct{} + SystemBase :: struct { - entities: map[EntityID]struct{}, // Treat as set + entities: EntitySet } SystemManager :: struct { @@ -12,29 +16,30 @@ SystemManager :: struct { systems: map[typeid]^SystemBase } -system_manager_create :: proc() -> SystemManager { - system_manager := SystemManager{ - signatures = make(map[typeid]Signature, context.allocator), - systems = make(map[typeid]^SystemBase, context.allocator), - } - - return system_manager +system_base_init :: proc(system_base: ^SystemBase) { + system_base.entities = make(EntitySet, context.allocator) } -system_manager_register_system :: proc($T: typeid, system_manager: ^SystemManager) -> ^T { - log.assertf(T not_in system_manager.systems, "Registering system more than once") - log.assertf(intrinsics.type_has_field(T, "entities"), "Registering non system type") +system_manager_init :: proc(system_manager: ^SystemManager) { + system_manager.signatures = make(map[typeid]Signature, context.allocator) + system_manager.systems = make(map[typeid]^SystemBase, context.allocator) +} - system := new(T, context.allocator) - system.entities = make(map[EntityID]struct{}) - system_manager.systems[T] = system +system_manager_register_system :: proc(system_manager: ^SystemManager, $System: typeid) -> ^System { + log.assertf(System not_in system_manager.systems, "Registering system more than once") + log.assertf(intrinsics.type_has_field(System, "entities"), "Registering non system type") + + system := new(System, context.allocator) + system_base_init(system) + + system_manager.systems[System] = system return system } -system_manager_set_signature :: proc($T: typeid, system_manager: ^SystemManager, signature: Signature) { - log.assertf(T in system_manager.systems, "System used before registered") - system_manager.signatures[T] = signature +system_manager_set_signature :: proc(system_manager: ^SystemManager, $System: typeid, signature: Signature) { + log.assertf(System in system_manager.systems, "System used before registered") + system_manager.signatures[System] = signature } system_manager_destroy_entity :: proc(system_manager: ^SystemManager, entity_id: EntityID) { @@ -54,7 +59,7 @@ system_manager_change_entity_signature :: proc(system_manager: ^SystemManager, e } } -system_manager_destroy :: proc(system_manager: ^SystemManager) { +system_manager_delete :: proc(system_manager: ^SystemManager) { for _, system in system_manager.systems { delete(system.entities) free(system) diff --git a/main.odin b/main.odin index e76e7f6..5501542 100644 --- a/main.odin +++ b/main.odin @@ -40,14 +40,13 @@ Globals :: struct { g: ^Globals default_context: runtime.Context +tracking_allocator: mem.Tracking_Allocator main :: proc() { context.logger = log.create_console_logger() - tracking_allocator: mem.Tracking_Allocator mem.tracking_allocator_init(&tracking_allocator, context.allocator) context.allocator = mem.tracking_allocator(&tracking_allocator) - defer reset_tracking_allocator(&tracking_allocator) default_context = context @@ -71,7 +70,7 @@ init_cb :: proc "c" () { sa.lock_mouse(true) g = new(Globals) - g.coordinator = ecs.coordinator_create() + ecs.coordinator_init(&g.coordinator) create_scene() } @@ -99,8 +98,10 @@ cleanup_cb :: proc "c" () { ecs.render_system_delete(g.render_system, &g.coordinator) - ecs.coordinator_destroy(&g.coordinator) + ecs.coordinator_delete(&g.coordinator) free(g) + + reset_tracking_allocator(&tracking_allocator) } event_cb :: proc "c" (event: ^sa.Event) { @@ -113,24 +114,22 @@ create_cube :: proc() { entity := ecs.coordinator_create_entity(&g.coordinator) ecs.coordinator_add_component( - ecs.GravityComponent, &g.coordinator, - entity, ecs.GravityComponent{ ecs.Vec3{ 0.0, program_config.GRAVITY_CONSTANT, 0.0 } - }) + }, + entity + ) ecs.coordinator_add_component( - ecs.RigidBodyComponent, &g.coordinator, - entity, ecs.RigidBodyComponent{ velocity = ecs.Vec3{ 0.0, 0.0, 0.0 }, acceleration = ecs.Vec3{ 0.0, 0.0, 0.0 }, - }) + }, + entity + ) ecs.coordinator_add_component( - ecs.TransformComponent, &g.coordinator, - entity, ecs.TransformComponent{ position = Vec3{ f32(rand.int_max(program_config.SPAWN_AREA)), @@ -139,108 +138,115 @@ create_cube :: proc() { }, rotation = ecs.Vec3{ 0.0, 0.0, 0.0 }, scale = ecs.Vec3{ 1.0, 1.0, 1.0 }, - }) - + }, + entity + ) ecs.coordinator_add_component( - ecs.ColorComponent, &g.coordinator, - entity, ecs.ColorComponent{ color = program_config.CUBE_COLORS[g.current_color] - }) + }, + entity + ) g.current_color += 1 g.current_color %= i32(len(program_config.CUBE_COLORS)) ecs.coordinator_add_component( - ecs.MeshComponent, &g.coordinator, - entity, ecs.MeshComponent{ mesh_id = .Cube - }) + }, + entity + ) ecs.coordinator_add_component( - ecs.MaterialComponent, &g.coordinator, - entity, ecs.MaterialComponent{ material_id = .Cube - }) + }, + entity + ) } create_scene :: proc() { - ecs.coordinator_register_component(ecs.GravityComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.RigidBodyComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.TransformComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.ColorComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.CameraComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.MaterialComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.MeshComponent, &g.coordinator) - ecs.coordinator_register_component(ecs.InputComponent, &g.coordinator) + coordinator := &g.coordinator - g.physics_system = ecs.coordinator_register_system(ecs.PhysicsSystem, &g.coordinator) - signature := ecs.signature_create() - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.GravityComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.RigidBodyComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.TransformComponent, &g.coordinator)) - ecs.coordinator_set_system_signature(ecs.PhysicsSystem, &g.coordinator, signature) + ecs.coordinator_register_component(coordinator, ecs.GravityComponent) + ecs.coordinator_register_component(coordinator, ecs.RigidBodyComponent) + ecs.coordinator_register_component(coordinator, ecs.TransformComponent) + ecs.coordinator_register_component(coordinator, ecs.ColorComponent) + ecs.coordinator_register_component(coordinator, ecs.CameraComponent) + ecs.coordinator_register_component(coordinator, ecs.MaterialComponent) + ecs.coordinator_register_component(coordinator, ecs.MeshComponent) + ecs.coordinator_register_component(coordinator, ecs.InputComponent) - g.render_system = ecs.coordinator_register_system(ecs.RenderSystem, &g.coordinator) + g.physics_system = ecs.coordinator_register_system(coordinator, ecs.PhysicsSystem) + signature := ecs.signature_make() + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.GravityComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.RigidBodyComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.TransformComponent)) + ecs.coordinator_set_system_signature(coordinator, ecs.PhysicsSystem, signature) + + g.render_system = ecs.coordinator_register_system(coordinator, ecs.RenderSystem) ecs.signature_clear(&signature) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.TransformComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.ColorComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.MeshComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.MaterialComponent, &g.coordinator)) - ecs.coordinator_set_system_signature(ecs.RenderSystem, &g.coordinator, signature) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.TransformComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.ColorComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.MeshComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.MaterialComponent)) + ecs.coordinator_set_system_signature(coordinator, ecs.RenderSystem, signature) - g.camera_system = ecs.coordinator_register_system(ecs.CameraSystem, &g.coordinator) + g.camera_system = ecs.coordinator_register_system(coordinator, ecs.CameraSystem) ecs.signature_clear(&signature) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.CameraComponent, &g.coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.InputComponent, &g.coordinator)) - ecs.coordinator_set_system_signature(ecs.CameraSystem, &g.coordinator, signature) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.CameraComponent)) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.InputComponent)) + ecs.coordinator_set_system_signature(coordinator, ecs.CameraSystem, signature) - g.input_system = ecs.coordinator_register_system(ecs.InputSystem, &g.coordinator) + g.input_system = ecs.coordinator_register_system(coordinator, ecs.InputSystem) ecs.signature_clear(&signature) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.InputComponent, &g.coordinator)) - ecs.coordinator_set_system_signature(ecs.InputSystem, &g.coordinator, signature) + ecs.signature_set(&signature, ecs.coordinator_get_component_id(coordinator, ecs.InputComponent)) + ecs.coordinator_set_system_signature(coordinator, ecs.InputSystem, signature) - user_entity := ecs.coordinator_create_entity(&g.coordinator) + user_entity := ecs.coordinator_create_entity(coordinator) ecs.coordinator_add_component( - ecs.CameraComponent, - &g.coordinator, - user_entity, + coordinator, ecs.CameraComponent{ position = program_config.START_POSITION, target = { 0, 0, 1 }, look = { 0, 0 }, - movement_speed = program_config.MOVEMENT_SPEED, look_sensitivity = program_config.LOOK_SENSITIVITY, - }) + }, + user_entity + ) ecs.coordinator_add_component( - ecs.InputComponent, - &g.coordinator, - user_entity, + coordinator, ecs.InputComponent{ key_down = {}, mouse_movement = Vec2{ 0, 0 } - }) + }, + user_entity + ) ecs.render_system_init(g.render_system, user_entity) } reset_tracking_allocator :: proc(track: ^mem.Tracking_Allocator) { + clean := true if len(track.allocation_map) > 0 { - fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) + fmt.eprintfln("=== %v allocations not freed: ===", len(track.allocation_map)) for _, entry in track.allocation_map { fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) } + clean = false } if len(track.bad_free_array) > 0 { - fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) + fmt.eprintfln("=== %v incorrect frees: ===", len(track.bad_free_array)) for entry in track.bad_free_array { fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) } + clean = false } + if clean do fmt.printfln("=== No memory leaked ===") + mem.tracking_allocator_destroy(track) }