package main import "base:runtime" import "base:intrinsics" import "core:log" import "core:mem" import "core:time" import "core:fmt" import "core:testing" import "core:strings" import "core:path/filepath" import "core:math" import "core:math/linalg" import "core:os" import "core:math/rand" import stbi "vendor:stb/image" import sa "sokol/app" import sh "sokol/helpers" import "ecs" Vec2 :: [2]f32 Vec3 :: [3]f32 Vec4 :: [4]f32 Globals :: struct { coordinator: ecs.Coordinator, physics_system: ^ecs.PhysicsSystem, render_system: ^ecs.RenderSystem, entities: []ecs.EntityID, } g: ^Globals mouse_move: Vec2 key_down: #sparse[sa.Keycode]bool default_context: runtime.Context 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 sa.run({ window_title = "Ecs Test", allocator = sa.Allocator(sh.allocator(&default_context)), logger = sa.Logger(sh.logger(&default_context)), init_cb = init_cb, frame_cb = frame_cb, cleanup_cb = cleanup_cb, event_cb = event_cb, }) } init_cb :: proc "c" () { context = default_context sa.show_mouse(false) sa.lock_mouse(true) g = new(Globals) g.coordinator = ecs.coordinator_create() create_scene() } frame_cb:: proc "c" () { context = default_context if key_down[.ESCAPE] { sa.quit() return } dt := f32(sa.frame_duration()) ecs.physics_system_update(g.physics_system, &g.coordinator, dt) ecs.render_system_update(g.render_system, &g.coordinator, dt, key_down, mouse_move) mouse_move = {} } cleanup_cb :: proc "c" () { context = default_context ecs.delete_render_system(g.render_system) delete(g.entities) ecs.coordinator_destroy(&g.coordinator) free(g) } event_cb :: proc "c" (event: ^sa.Event) { context = default_context #partial switch event.type { case .MOUSE_MOVE: mouse_move += {event.mouse_dx, event.mouse_dy} case .KEY_DOWN: key_down[event.key_code] = true case .KEY_UP: key_down[event.key_code] = false } } create_scene :: proc() { ecs.coordinator_register_component(ecs.Gravity, &g.coordinator) ecs.coordinator_register_component(ecs.RigidBody, &g.coordinator) ecs.coordinator_register_component(ecs.Transform, &g.coordinator) ecs.coordinator_register_component(ecs.Color, &g.coordinator) g.physics_system = ecs.coordinator_register_system(ecs.PhysicsSystem, &g.coordinator) g.render_system = ecs.coordinator_register_system(ecs.RenderSystem, &g.coordinator) ecs.init_render_system(g.render_system) signature := ecs.signature_create() ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Gravity, &g.coordinator)) ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.RigidBody, &g.coordinator)) ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Transform, &g.coordinator)) ecs.coordinator_set_system_signature(ecs.PhysicsSystem, &g.coordinator, signature) signature = ecs.signature_create() ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Transform, &g.coordinator)) ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Color, &g.coordinator)) ecs.coordinator_set_system_signature(ecs.RenderSystem, &g.coordinator, signature) g.entities = make([]ecs.EntityID, ecs.ENTITY_MAX) for &entity in g.entities { entity = ecs.coordinator_create_entity(&g.coordinator) ecs.coordinator_add_component( ecs.Gravity, &g.coordinator, entity, ecs.Gravity{ ecs.Vec3{0.0, -2.82, 0.0} }) ecs.coordinator_add_component( ecs.RigidBody, &g.coordinator, entity, ecs.RigidBody{ velocity = ecs.Vec3{0.0, 0.0, 0.0}, acceleration = ecs.Vec3{0.0, 0.0, 0.0}, }) ecs.coordinator_add_component( ecs.Transform, &g.coordinator, entity, ecs.Transform{ position = Vec3{ f32(rand.int_max(50)), f32(rand.int_max(10)), f32(rand.int_max(50)), }, rotation = ecs.Vec3{0.0, 0.0, 0.0}, scale = ecs.Vec3{1.0, 1.0, 1.0}, }) ecs.coordinator_add_component( ecs.Color, &g.coordinator, entity, ecs.Color{ color = Vec4{ rand.float32_uniform(0,1), rand.float32_uniform(0,1), rand.float32_uniform(0,1), rand.float32_uniform(0,1), }, }) } } reset_tracking_allocator :: proc(track: ^mem.Tracking_Allocator) { if len(track.allocation_map) > 0 { fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) for _, entry in track.allocation_map { fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) } } if len(track.bad_free_array) > 0 { fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) for entry in track.bad_free_array { fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) } } mem.tracking_allocator_destroy(track) }