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" import program_config "config" Vec2 :: ecs.Vec2 Vec3 :: ecs.Vec3 Vec4 :: ecs.Vec4 Globals :: struct { coordinator: ecs.Coordinator, input_system: ^ecs.InputSystem, physics_system: ^ecs.PhysicsSystem, camera_system: ^ecs.CameraSystem, render_system: ^ecs.RenderSystem, time_since_cube: f32, current_color: i32, } g: ^Globals default_context: runtime.Context tracking_allocator: mem.Tracking_Allocator main :: proc() { context.logger = log.create_console_logger() mem.tracking_allocator_init(&tracking_allocator, context.allocator) context.allocator = mem.tracking_allocator(&tracking_allocator) default_context = context sa.run({ window_title = program_config.WINDOW_TITLE, 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) ecs.coordinator_init(&g.coordinator) create_scene() } frame_cb:: proc "c" () { context = default_context dt := f32(sa.frame_duration()) g.time_since_cube += dt if g.time_since_cube >= program_config.SPAWN_INTERVAL { g.time_since_cube = 0 create_cube() } ecs.physics_system_update(g.physics_system, &g.coordinator, dt) ecs.camera_system_update(g.camera_system, &g.coordinator, dt) ecs.render_system_update(g.render_system, &g.coordinator) ecs.input_system_mouse_reset(g.input_system, &g.coordinator) } cleanup_cb :: proc "c" () { context = default_context ecs.render_system_delete(g.render_system, &g.coordinator) ecs.coordinator_delete(&g.coordinator) free(g) reset_tracking_allocator(&tracking_allocator) } event_cb :: proc "c" (event: ^sa.Event) { context = default_context ecs.input_system_update(g.input_system, &g.coordinator, event) } create_cube :: proc() { entity := ecs.coordinator_create_entity(&g.coordinator) ecs.coordinator_add_component( &g.coordinator, ecs.GravityComponent{ ecs.Vec3{ 0.0, program_config.GRAVITY_CONSTANT, 0.0 } }, entity ) ecs.coordinator_add_component( &g.coordinator, 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( &g.coordinator, ecs.TransformComponent{ position = Vec3{ f32(rand.int_max(program_config.SPAWN_AREA)), 10, f32(rand.int_max(program_config.SPAWN_AREA)), }, rotation = ecs.Vec3{ 0.0, 0.0, 0.0 }, scale = ecs.Vec3{ 1.0, 1.0, 1.0 }, }, entity ) ecs.coordinator_add_component( &g.coordinator, 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( &g.coordinator, ecs.MeshComponent{ mesh_id = .Cube }, entity ) ecs.coordinator_add_component( &g.coordinator, ecs.MaterialComponent{ material_id = .Cube }, entity ) } create_scene :: proc() { coordinator := &g.coordinator 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.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_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(coordinator, ecs.CameraSystem) ecs.signature_clear(&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(coordinator, ecs.InputSystem) ecs.signature_clear(&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(coordinator) ecs.coordinator_add_component( 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( 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.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.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) }