diff --git a/Makefile b/Makefile index bcc58bf..3f9bd52 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,25 @@ build-shaders: - ./sokol-shdc -i shader.glsl -o shader.odin -l metal_macos -f sokol_odin + ./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/README.md b/README.md new file mode 100644 index 0000000..be6f42f --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# ECS Test + +A project where I created a simple ECS in Odin to test performance/developer experience. The project uses Sokol to render the scene. + +![Example GIF of application](examples/example.gif) diff --git a/config/program_config.odin b/config/program_config.odin new file mode 100644 index 0000000..7ced000 --- /dev/null +++ b/config/program_config.odin @@ -0,0 +1,28 @@ +package program_config + +import sg "../sokol/gfx" + +// Application +WINDOW_TITLE :: "ECS Test" + +// Behaviour +SPAWN_INTERVAL :: 0.05 // in seconds +GRAVITY_CONSTANT :: -2.5 +SPAWN_AREA :: 30 // one side +Y_DESPAWN_CUTOFF :: -15 + +// Colors +BACKGROUND_COLOR :: sg.Color{ 1.0000, 0.9725, 0.9059, 1 } +CUBE_COLORS := [][4]f32{ + { 0.6235, 0.7725, 0.9098, 1 }, + { 0.9216, 0.6392, 0.6392, 1 }, + { 0.7137, 0.8431, 0.6588, 1 }, + { 0.7059, 0.6549, 0.8392, 1 }, + { 1.0000, 0.8980, 0.6000, 1 }, +} +BORDER_COLOR :: [4]f32{ 0, 0, 0, 1 } + +// User +MOVEMENT_SPEED :: 3.0 +LOOK_SENSITIVITY :: 0.15 +START_POSITION :: [3]f32{ 15, 0, 60 } diff --git a/ecs/camera_system.odin b/ecs/camera_system.odin new file mode 100644 index 0000000..e6dc7e2 --- /dev/null +++ b/ecs/camera_system.odin @@ -0,0 +1,47 @@ +package ecs + +import "core:math" +import "core:math/linalg" + +CameraSystem :: struct { + using _: SystemBase, +} + +camera_system_update :: proc(camera_system: ^CameraSystem, coordinator: ^Coordinator, dt: f32) { + 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 + else if input.key_down[.S] do move_input.y = -1 + + if input.key_down[.D] do move_input.x = 1 + else if input.key_down[.A] do move_input.x = -1 + + if input.key_down[.SPACE] do move_input.z = 1 + else if input.key_down[.LEFT_SHIFT] do move_input.z = -1 + + look_input: Vec2 = -input.mouse_movement * camera.look_sensitivity + camera.look += look_input + camera.look.x = math.wrap(camera.look.x, 360) + camera.look.y = math.clamp(camera.look.y, -89.5, 89.5) + + look_mat := linalg.matrix4_from_yaw_pitch_roll_f32( + linalg.to_radians(camera.look.x), + linalg.to_radians(camera.look.y), + 0, + ) + + forward := (look_mat * Vec4{0, 0, -1, 1}).xyz + right := (look_mat * Vec4{1, 0, 0, 1}).xyz + up := (look_mat * Vec4{0, 1, 0, 1}).xyz + + move_dir := forward * move_input.y + right * move_input.x + up * move_input.z + motion := linalg.normalize0(move_dir) * camera.movement_speed * dt + camera.position += motion + + camera.target = camera.position + forward + } + +} diff --git a/ecs/component_manager.odin b/ecs/component_manager.odin index 562bb14..5cc6f10 100644 --- a/ecs/component_manager.odin +++ b/ecs/component_manager.odin @@ -1,66 +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), - 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) + + 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($Component: typeid, component_manager: ^ComponentManager) { + log.assertf(Component not_in component_manager.component_ids, "Registering component more than once") + + component_manager.component_ids[Component] = component_manager.next_component_id + + component_pool := new(ComponentPool(Component), context.allocator) + component_pool_init(component_pool) + + 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) + } } - return component_manager + 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_register_component :: proc($T: typeid, component_manager: ^ComponentManager) { - log.assertf(T not_in component_manager.component_types, "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.next_component_type += 1 +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_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_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_add_component :: proc($T: typeid, component_manager: ^ComponentManager, entity_id: EntityID, component: T) { - component_pool := cast(^ComponentPool(T))component_manager.component_pools[T] - component_pool_insert_data(T, component_pool, entity_id, component) +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_remove_component :: proc($T: typeid, component_manager: ^ComponentManager, entity_id: EntityID) { - component_pool := cast(^ComponentPool(T))component_manager.component_pools[T] - component_pool_remove_data(T, 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] - return component_pool_get(T, component_pool, entity_id) +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 _, component_pool in component_manager.component_pools { - component_pool_destroy_entity(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 80efcb9..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($T: typeid, 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($T: typeid, component_pool: ^ComponentPool(T) component_pool.size += 1 } -component_pool_remove_data :: proc(component_pool: ^ComponentPool(any), 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(any), entity_i component_pool.size -= 1 } -component_pool_get :: proc($T: typeid, 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(any), 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(any)) { +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/components.odin b/ecs/components.odin new file mode 100644 index 0000000..6a4f5ce --- /dev/null +++ b/ecs/components.odin @@ -0,0 +1,60 @@ +package ecs + +import sa "../sokol/app" +import sg "../sokol/gfx" + +Mat4 :: matrix[4, 4]f32 + +Vec2 :: [2]f32 +Vec3 :: [3]f32 +Vec4 :: [4]f32 + +GravityComponent :: struct { + force: Vec3 +} + +RigidBodyComponent :: struct { + velocity: Vec3, + acceleration: Vec3, +} + +TransformComponent :: struct { + position: Vec3, + rotation: Vec3, + scale: Vec3, +} + +ColorComponent :: struct { + color: Vec4, +} + +MeshID :: enum { + Cube, +} + +MeshComponent :: struct { + mesh_id: MeshID +} + +MaterialID :: enum { + Cube, + Outline, +} + +MaterialComponent :: struct { + material_id: MaterialID +} + +CameraComponent :: struct { + position: Vec3, + target: Vec3, + look: Vec2, + + look_sensitivity: f32, + movement_speed: f32, +} + +InputComponent :: struct { + mouse_movement: Vec2, + key_down: #sparse[sa.Keycode]bool, +} diff --git a/ecs/constants.odin b/ecs/constants.odin index c0c3af9..5a5c4b8 100644 --- a/ecs/constants.odin +++ b/ecs/constants.odin @@ -6,4 +6,4 @@ COMPONENT_MAX :: 32 ID :: u32 EntityID :: ID -ComponentType :: u8 +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 new file mode 100644 index 0000000..b36140d --- /dev/null +++ b/ecs/input_system.odin @@ -0,0 +1,32 @@ +package ecs + +import sa "../sokol/app" + +InputSystem :: struct { + using _: SystemBase, +} + +input_system_update :: proc(input_system: ^InputSystem, coordinator: ^Coordinator, event: ^sa.Event) { + for entity_id in input_system.entities { + input := coordinator_get_component(coordinator, InputComponent, entity_id) + + #partial switch event.type { + case .MOUSE_MOVE: + input.mouse_movement += {event.mouse_dx, event.mouse_dy} + case .KEY_DOWN: + input.key_down[event.key_code] = true + case .KEY_UP: + input.key_down[event.key_code] = false + } + + if input.key_down[.ESCAPE] do sa.quit() + } +} + +input_system_mouse_reset :: proc(input_system: ^InputSystem, coordinator: ^Coordinator) { + for entity_id in input_system.entities { + input_id := coordinator_get_component(coordinator, InputComponent, entity_id) + + input_id.mouse_movement = { 0, 0 } + } +} diff --git a/ecs/physics_system.odin b/ecs/physics_system.odin index 39e2b4f..be5bad3 100644 --- a/ecs/physics_system.odin +++ b/ecs/physics_system.odin @@ -1,34 +1,31 @@ package ecs -Vec3 :: distinct [3]f32 +import "core:log" -Gravity :: struct { - force: Vec3 -} - -RigidBody :: struct { - velocity: Vec3, - acceleration: Vec3, -} - -Transform :: struct { - position: Vec3, - rotation: Vec3, - scale: Vec3, -} +import program_config "../config" PhysicsSystem :: struct { - using base: SystemBase, + using _: SystemBase, } - physics_system_update :: proc(physics_system: ^PhysicsSystem, coordinator: ^Coordinator, dt: f32) { - for entity in physics_system.entities { - rigid_body := coordinator_get_component(RigidBody, coordinator, entity) - transform := coordinator_get_component(Transform, coordinator, entity) - gravity := coordinator_get_component(Gravity, coordinator, entity) + entities_to_delete := make([dynamic]EntityID) + defer delete(entities_to_delete) + + 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_id) + } + } + + for entity in entities_to_delete { + coordinator_destroy_entity(coordinator, entity) } } diff --git a/ecs/render_system.odin b/ecs/render_system.odin index ff041e9..82f9843 100644 --- a/ecs/render_system.odin +++ b/ecs/render_system.odin @@ -1,10 +1,324 @@ package ecs +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 stbi "vendor:stb/image" + +import sa "../sokol/app" +import sl "../sokol/log" +import sh "../sokol/helpers" +import sg "../sokol/gfx" + +import program_config "../config" + +import shaders "../shaders/out" + +VertexData :: struct { + pos: Vec3, +} + +Mesh :: struct { + vertex_buffer: sg.Buffer, + index_buffer: sg.Buffer, +} + +Material :: struct { + pipeline: sg.Pipeline, + shader: sg.Shader, +} + RenderSystem :: struct { - using base: SystemBase, + using _: SystemBase, + user_entity: EntityID, + + materials: map[MaterialID]Material, + meshes : map[MeshID]Mesh, +} + +@(private="file") +init_outline_material :: proc(render_system: ^RenderSystem) { + shader := sg.make_shader(shaders.outline_shader_desc(sg.query_backend())) + pipeline := sg.make_pipeline({ + shader = shader, + layout = { + attrs = { + shaders.ATTR_outline_pos = { format = .FLOAT3 }, + }, + }, + index_type = .UINT16, + cull_mode = .BACK, + depth = { + pixel_format = .DEFAULT, + write_enabled = true, + bias = 0.001, + bias_clamp = 0.0, + bias_slope_scale = 1.0, + compare = .LESS_EQUAL, + }, + sample_count = 4, + }) + + render_system.materials[.Outline] = Material{ + shader = shader, + pipeline = pipeline, + } +} + +@(private="file") +init_cube_material :: proc(render_system: ^RenderSystem) { + shader := sg.make_shader(shaders.cube_shader_desc(sg.query_backend())) + pipeline := sg.make_pipeline({ + shader = shader, + layout = { + attrs = { + shaders.ATTR_cube_pos = { format = .FLOAT3 }, + }, + }, + index_type = .UINT16, + cull_mode = .FRONT, + depth = { + pixel_format = .DEFAULT, + write_enabled = true, + bias = 0.001, + bias_clamp = 0.0, + bias_slope_scale = 1.0, + compare = .LESS_EQUAL, + }, + sample_count = 4, + }) + + render_system.materials[.Cube] = Material{ + shader = shader, + pipeline = pipeline, + } +} + +@(private="file") +init_cube_mesh :: proc (render_system: ^RenderSystem) { + cube_vertices := []VertexData { + { pos = { -0.5, -0.5, 0.5 }, }, + { pos = { 0.5, -0.5, 0.5 }, }, + { pos = { 0.5, 0.5, 0.5 }, }, + { pos = { -0.5, 0.5, 0.5 }, }, + + { pos = { -0.5, -0.5, -0.5 }, }, + { pos = { 0.5, -0.5, -0.5 }, }, + { pos = { 0.5, 0.5, -0.5 }, }, + { pos = { -0.5, 0.5, -0.5 }, }, + + { pos = { -0.5, 0.5, 0.5 }, }, + { pos = { 0.5, 0.5, 0.5 }, }, + { pos = { 0.5, 0.5, -0.5 }, }, + { pos = { -0.5, 0.5, -0.5 }, }, + + { pos = { -0.5, -0.5, 0.5 }, }, + { pos = { 0.5, -0.5, 0.5 }, }, + { pos = { 0.5, -0.5, -0.5 }, }, + { pos = { -0.5, -0.5, -0.5 }, }, + + { pos = { 0.5, -0.5, 0.5 }, }, + { pos = { 0.5, -0.5, -0.5 }, }, + { pos = { 0.5, 0.5, -0.5 }, }, + { pos = { 0.5, 0.5, 0.5 }, }, + + { pos = { -0.5, -0.5, 0.5 }, }, + { pos = { -0.5, -0.5, -0.5 }, }, + { pos = { -0.5, 0.5, -0.5 }, }, + { pos = { -0.5, 0.5, 0.5 }, }, + } + vertex_buffer := sg.make_buffer({ + data = sg_range(cube_vertices) + }) + + cube_indices := []u16 { + 0, 1, 2, 0, 2, 3, + 6, 5, 4, 7, 6, 4, + 8, 9, 10, 8, 10, 11, + 14, 13, 12, 15, 14, 12, + 16, 17, 18, 16, 18, 19, + 22, 21, 20, 23, 22, 20, + } + + index_buffer := sg.make_buffer({ + usage = { index_buffer = true }, + data = sg_range(cube_indices), + }) + + render_system.meshes[.Cube] = Mesh{ + vertex_buffer = vertex_buffer, + index_buffer = index_buffer, + } +} + +render_system_init :: proc(render_system: ^RenderSystem, user_entity: EntityID) { + default_context := runtime.default_context() + + sg.setup({ + environment = sh.glue_environment(), + allocator = sg.Allocator(sh.allocator(&default_context)), + logger = sg.Logger( { func = sl.func } ), + }) + + render_system.materials = make(map[MaterialID]Material) + render_system.meshes = make(map[MeshID]Mesh) + render_system.user_entity = user_entity + + init_cube_mesh(render_system) + init_cube_material(render_system) + + init_outline_material(render_system) +} + +render_system_delete :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator) { + cube_mesh := render_system.meshes[.Cube] + sg.destroy_buffer(cube_mesh.index_buffer) + sg.destroy_buffer(cube_mesh.vertex_buffer) + + cube_material := render_system.materials[.Cube] + sg.destroy_pipeline(cube_material.pipeline) + sg.destroy_shader(cube_material.shader) + + outline_material := render_system.materials[.Outline] + sg.destroy_pipeline(outline_material.pipeline) + sg.destroy_shader(outline_material.shader) + + delete(render_system.materials) + delete(render_system.meshes) + + sg.shutdown() +} + +@(private="file") +CLEAR_SCREEN_ACTION :: sg.Pass_Action{ + colors = { + 0 = { + load_action = .CLEAR, + clear_value = program_config.BACKGROUND_COLOR, + }, + }, +} + +@(private="file") +outline_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) { + 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) + rot_mat := linalg.matrix4_from_yaw_pitch_roll_f32( + transform.rotation.y, + transform.rotation.x, + transform.rotation.z + ) + pos_mat := linalg.matrix4_translate_f32(transform.position) + model := pos_mat * rot_mat * scale_mat + mvp := proj * view * model + + outline_material := render_system.materials[.Outline] + sg.apply_pipeline(outline_material.pipeline) + + sg.apply_bindings({ + vertex_buffers = { 0 = mesh.vertex_buffer }, + index_buffer = mesh.index_buffer, + }) + + sg.apply_uniforms(shaders.UB_VsParamsOutline, sg_range(&shaders.Vsparamsoutline{ + mvp = mvp, + })) + + sg.apply_uniforms(shaders.UB_FsParamsOutline, sg_range(&shaders.Fsparamsoutline{ + col = program_config.BORDER_COLOR, + })) + + + sg.draw(0, 36, 1) + } +} + + +@(private="file") +cube_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) { + 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] + + material_id := coordinator_get_component(coordinator, MaterialComponent, entity_id).material_id + material := render_system.materials[material_id] + + 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( + transform.rotation.y, + transform.rotation.x, + transform.rotation.z + ) + pos_mat := linalg.matrix4_translate_f32(transform.position) + model := pos_mat * rot_mat * scale_mat + mvp := proj * view * model + + sg.apply_pipeline(material.pipeline) + sg.apply_bindings({ + vertex_buffers = { 0 = mesh.vertex_buffer }, + index_buffer = mesh.index_buffer, + }) + + sg.apply_uniforms(shaders.UB_VsParamsCube, sg_range(&shaders.Vsparamscube{ + mvp = mvp, + col = color.color, + })) + + sg.draw(0, 36, 1) + } } render_system_update :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator) { - for entity in render_system.entities { + 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 } ) + + sg.begin_pass({ swapchain = sh.glue_swapchain(), action = CLEAR_SCREEN_ACTION }) + cube_pass(render_system, coordinator, proj, view) + outline_pass(render_system, coordinator, proj, view) + sg.end_pass() + + 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), + size = len(s) * size_of(T), + } +} + +@(private="file") +sg_range_from_struct :: proc(s: ^$T) -> sg.Range where intrinsics.type_is_struct(T) { + return { + ptr = s, + size = size_of(T), } } 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/examples/example.gif b/examples/example.gif new file mode 100644 index 0000000..923e5d8 Binary files /dev/null and b/examples/example.gif differ diff --git a/main.odin b/main.odin index f8d091e..c32f5c9 100644 --- a/main.odin +++ b/main.odin @@ -13,405 +13,244 @@ 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 sg "sokol/app" +import sl "sokol/log" import sh "sokol/helpers" -import sg "sokol/gfx" import "ecs" +import program_config "config" -Vec2 :: [2]f32 -Vec3 :: [3]f32 -Vec4 :: [4]f32 - -Mat4 :: matrix[4, 4]f32 - -VertexData :: struct { - pos: Vec3, - col: sg.Color, - uv: Vec2, -} - -Scene :: struct { - physics_system: ^ecs.PhysicsSystem, - entities: []ecs.EntityID, -} +Vec2 :: ecs.Vec2 +Vec3 :: ecs.Vec3 +Vec4 :: ecs.Vec4 Globals :: struct { - shader: sg.Shader, - pipeline: sg.Pipeline, - vertex_buffer: sg.Buffer, - index_buffer: sg.Buffer, - image: sg.Image, - sampler: sg.Sampler, - rotation: f32, - - camera: struct { - pos: Vec3, - target: Vec3, - look: Vec2, - }, - coordinator: ecs.Coordinator, - scene: Scene, - dt: f32, + 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 -mouse_move: Vec2 -key_down: #sparse[sa.Keycode]bool - 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) + mem.tracking_allocator_init(&tracking_allocator, context.allocator) + context.allocator = mem.tracking_allocator(&tracking_allocator) default_context = context sa.run({ - window_title = "Ecs Test", + window_title = program_config.WINDOW_TITLE, allocator = sa.Allocator(sh.allocator(&default_context)), - logger = sa.Logger(sh.logger(&default_context)), + logger = sg.Logger( { func = sl.func } ), + + sample_count = 4, init_cb = init_cb, frame_cb = frame_cb, cleanup_cb = cleanup_cb, event_cb = event_cb, }) - - g.coordinator = ecs.coordinator_create() - defer ecs.coordinator_destroy(&g.coordinator) - - g.scene = create_scene(&g.coordinator) - defer delete(g.scene.entities) } init_cb :: proc "c" () { context = default_context - sg.setup({ - environment = sh.glue_environment(), - allocator = sg.Allocator(sh.allocator(&default_context)), - logger = sg.Logger(sh.logger(&default_context)), - }) sa.show_mouse(false) sa.lock_mouse(true) g = new(Globals) + ecs.coordinator_init(&g.coordinator) - g.camera = { - pos = { 0, 0, 2 }, - target = { 0, 0, 1 }, - } - - g.shader = sg.make_shader(main_shader_desc(sg.query_backend())) - g.pipeline = sg.make_pipeline({ - shader = g.shader, - layout = { - attrs = { - ATTR_main_pos = { format = .FLOAT3 }, - ATTR_main_col = { format = .FLOAT4 }, - ATTR_main_uv = { format = .FLOAT2 }, - }, - }, - index_type = .UINT16, - cull_mode = .BACK, - depth = { - pixel_format = .DEFAULT, - write_enabled = true, - bias = 0.001, - bias_clamp = 0.0, - bias_slope_scale = 1.0, - compare = .LESS_EQUAL, - }, - }) - - vertices := []VertexData { - { pos = { -0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { 0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { 0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - { pos = { -0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - - { pos = { -0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { 0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { 0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - { pos = { -0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - - { pos = { -0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { 0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { 0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - { pos = { -0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - - { pos = { -0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { 0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { 0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - { pos = { -0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - - { pos = { 0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { 0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { 0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - { pos = { 0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - - { pos = { -0.5, -0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 0 } }, - { pos = { -0.5, -0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 0 } }, - { pos = { -0.5, 0.5, -0.5 }, col = { 1, 1, 1, 1 }, uv = { 0, 1 } }, - { pos = { -0.5, 0.5, 0.5 }, col = { 1, 1, 1, 1 }, uv = { 1, 1 } }, - } - g.vertex_buffer = sg.make_buffer({ - data = sg_range(vertices) - }) - - indices := []u16 { - 1, 0, 2, - 3, 2, 0, - 7, 4, 6, - 5, 6, 4, - 9, 8, 10, - 11, 10, 8, - 15, 12, 14, - 13, 14, 12, - 17, 16, 18, - 19, 18, 16, - 23, 20, 22, - 21, 22, 20, - } - - g.index_buffer = sg.make_buffer({ - usage = { index_buffer = true }, - data = sg_range(indices), - }) - - w, h: i32 - pixels := stbi.load("res/texture_blue.png", &w, &h, nil, 4) - assert(pixels != nil) - defer(stbi.image_free(pixels)) - - g.image = sg.make_image({ - width = w, - height = h, - pixel_format = .RGBA8, - data = { - subimage = { - 0 = { - 0 = { - ptr = pixels, - size = uint(w * h * 4) - } - } - } - } - }) - - g.sampler = sg.make_sampler({}) + create_scene() } frame_cb:: proc "c" () { context = default_context - - if key_down[.ESCAPE] { - sa.quit() - return + + 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() } - start_time := time.now() - //ecs.physics_system_update(g.scene.physics_system, &g.coordinator, g.dt) // seg fault + 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) - g.dt = f32(sa.frame_duration()) - - update_camera(g.dt) - - g.rotation += linalg.to_radians(50 * g.dt) - - proj := linalg.matrix4_perspective_f32(70, sa.widthf() / sa.heightf(), 0.001, 1000) - view := linalg.matrix4_look_at_f32(g.camera.pos, g.camera.target, { 0, 1, 0 } ) - - Object :: struct { - pos: Vec3, - rot: Vec3, - } - objects := []Object { - { { -2, 0, 0 }, { 0, 0, 0 } }, - { { 0, 0, 0 }, { 0, 0, 0 } }, - { { 2, 0, 0 }, { 0, 0, 0 } }, - } - - sg.begin_pass({ swapchain = sh.glue_swapchain() }) - - sg.apply_pipeline(g.pipeline) - sg.apply_bindings({ - vertex_buffers = { 0 = g.vertex_buffer }, - index_buffer = g.index_buffer, - images = { IMG_tex = g.image }, - samplers = { SMP_smp = g.sampler }, - }) - - for obj in objects { - model := linalg.matrix4_translate_f32(obj.pos) * linalg.matrix4_from_yaw_pitch_roll_f32(obj.rot.y, obj.rot.x, obj.rot.z) - - sg.apply_uniforms(UB_VsParams, sg_range(&Vsparams { - mvp = proj * view * model - })) - - sg.draw(0, 36, 1) - } - - - sg.end_pass() - sg.commit() - - mouse_move = {} -} - -update_camera :: proc(dt: f32) { - MOVE_SPEED :: 3 - LOOK_SENSITIVITY :: 0.15 - - move_input: Vec3 - if key_down[.W] do move_input.y = 1 - else if key_down[.S] do move_input.y = -1 - - if key_down[.D] do move_input.x = 1 - else if key_down[.A] do move_input.x = -1 - - if key_down[.SPACE] do move_input.z = 1 - else if key_down[.LEFT_SHIFT] do move_input.z = -1 - - look_input: Vec2 = -mouse_move * LOOK_SENSITIVITY - g.camera.look += look_input - g.camera.look.x = math.wrap(g.camera.look.x, 360) - g.camera.look.y = math.clamp(g.camera.look.y, -89.5, 89.5) - - look_mat := linalg.matrix4_from_yaw_pitch_roll_f32( - linalg.to_radians(g.camera.look.x), - linalg.to_radians(g.camera.look.y), - 0, - ) - - forward := (look_mat * Vec4{0, 0, -1, 1}).xyz - right := (look_mat * Vec4{1, 0, 0, 1}).xyz - up := (look_mat * Vec4{0, 1, 0, 1}).xyz - - move_dir := forward * move_input.y + right * move_input.x + up * move_input.z - motion := linalg.normalize0(move_dir) * MOVE_SPEED * dt - g.camera.pos += motion - - g.camera.target = g.camera.pos + forward + ecs.input_system_mouse_reset(g.input_system, &g.coordinator) } cleanup_cb :: proc "c" () { context = default_context - sg.destroy_buffer(g.index_buffer) - sg.destroy_buffer(g.vertex_buffer) - sg.destroy_image(g.image) - sg.destroy_sampler(g.sampler) - sg.destroy_pipeline(g.pipeline) - sg.destroy_shader(g.shader) + ecs.render_system_delete(g.render_system, &g.coordinator) + ecs.coordinator_delete(&g.coordinator) free(g) - sg.shutdown() + + reset_tracking_allocator(&tracking_allocator) } 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 - } + ecs.input_system_update(g.input_system, &g.coordinator, event) } -create_scene :: proc(coordinator: ^ecs.Coordinator) -> Scene { - scene := Scene{} +create_cube :: proc() { + entity := ecs.coordinator_create_entity(&g.coordinator) - ecs.coordinator_register_component(ecs.Gravity, coordinator) - ecs.coordinator_register_component(ecs.RigidBody, coordinator) - ecs.coordinator_register_component(ecs.Transform, coordinator) - - scene.physics_system = ecs.coordinator_register_system(ecs.PhysicsSystem, 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)) - signature := ecs.signature_create() - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Gravity, coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.RigidBody, coordinator)) - ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Transform, coordinator)) - ecs.coordinator_set_system_signature(ecs.PhysicsSystem, coordinator, signature) - - scene.entities = make([]ecs.EntityID, ecs.ENTITY_MAX) - for &entity in scene.entities { - entity = ecs.coordinator_create_entity(coordinator) - - ecs.coordinator_add_component( - ecs.Gravity, - coordinator, - entity, - ecs.Gravity{ - ecs.Vec3{0.0, -9.82, 0.0} - }) - ecs.coordinator_add_component( - ecs.RigidBody, - 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, - coordinator, - entity, - ecs.Transform{ - position = ecs.Vec3{0.0, 0.0, 0.0}, - rotation = ecs.Vec3{0.0, 0.0, 0.0}, - scale = ecs.Vec3{1.0, 1.0, 1.0}, - }) - } - - return scene + ecs.coordinator_add_component( + &g.coordinator, + ecs.MeshComponent{ + mesh_id = .Cube + }, + entity + ) + ecs.coordinator_add_component( + &g.coordinator, + ecs.MaterialComponent{ + material_id = .Cube + }, + entity + ) } -sg_range :: proc { - sg_range_from_slice, - sg_range_from_struct, -} +create_scene :: proc() { + coordinator := &g.coordinator -sg_range_from_slice :: proc(s: []$T) -> sg.Range { - return { - ptr = raw_data(s), - size = len(s) * size_of(T), - } -} + 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) -sg_range_from_struct :: proc(s: ^$T) -> sg.Range where intrinsics.type_is_struct(T) { - return { - ptr = s, - size = size_of(T), - } + 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.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) - } + 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) } - 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) - } + 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) } - mem.tracking_allocator_destroy(track) + clean = false + } + if clean do fmt.printfln("=== No memory leaked ===") + + mem.tracking_allocator_destroy(track) } diff --git a/res/texture_blue.png b/res/texture_blue.png deleted file mode 100644 index e069832..0000000 Binary files a/res/texture_blue.png and /dev/null differ diff --git a/res/texture_green.png b/res/texture_green.png deleted file mode 100644 index 99fa4ce..0000000 Binary files a/res/texture_green.png and /dev/null differ diff --git a/res/texture_orange.png b/res/texture_orange.png deleted file mode 100644 index 916ba29..0000000 Binary files a/res/texture_orange.png and /dev/null differ diff --git a/res/texture_pink.png b/res/texture_pink.png deleted file mode 100644 index b47f7b2..0000000 Binary files a/res/texture_pink.png and /dev/null differ diff --git a/res/texture_purple.png b/res/texture_purple.png deleted file mode 100644 index 40b1f8a..0000000 Binary files a/res/texture_purple.png and /dev/null differ diff --git a/res/texture_red.png b/res/texture_red.png deleted file mode 100644 index c9b3fe0..0000000 Binary files a/res/texture_red.png and /dev/null differ diff --git a/res/texture_yellow.png b/res/texture_yellow.png deleted file mode 100644 index 18d1f03..0000000 Binary files a/res/texture_yellow.png and /dev/null differ diff --git a/shader.glsl b/shader.glsl deleted file mode 100644 index 6529946..0000000 --- a/shader.glsl +++ /dev/null @@ -1,41 +0,0 @@ -@header package main -@header import sg "sokol/gfx" - -@ctype mat4 Mat4 - -@vs vs -in vec3 pos; -in vec4 col; -in vec2 uv; - -layout(binding = 0) uniform VsParams { - mat4 mvp; -}; - -out vec4 color; -out vec2 tex_coord; - -void main() { - gl_Position = mvp * vec4(pos, 1); - color = col; - tex_coord = uv; -} - -@end - -@fs fs -in vec4 color; -in vec2 tex_coord; - -layout(binding=0) uniform texture2D tex; -layout(binding=0) uniform sampler smp; - -out vec4 frag_color; - -void main() { - frag_color = texture(sampler2D(tex, smp), tex_coord) * color; -} - -@end - -@program main vs fs diff --git a/shader.odin b/shader.odin deleted file mode 100644 index 531fc43..0000000 --- a/shader.odin +++ /dev/null @@ -1,207 +0,0 @@ -package main -import sg "sokol/gfx" -/* - #version:1# (machine generated, don't edit!) - - Generated by sokol-shdc (https://github.com/floooh/sokol-tools) - - Cmdline: - sokol-shdc -i shader.glsl -o shader.odin -l metal_macos -f sokol_odin - - Overview: - ========= - Shader program: 'main': - Get shader desc: main_shader_desc(sg.query_backend()) - Vertex Shader: vs - Fragment Shader: fs - Attributes: - ATTR_main_pos => 0 - ATTR_main_col => 1 - ATTR_main_uv => 2 - Bindings: - Uniform block 'VsParams': - Odin struct: Vsparams - Bind slot: UB_VsParams => 0 - Image 'tex': - Image type: ._2D - Sample type: .FLOAT - Multisampled: false - Bind slot: IMG_tex => 0 - Sampler 'smp': - Type: .FILTERING - Bind slot: SMP_smp => 0 -*/ -ATTR_main_pos :: 0 -ATTR_main_col :: 1 -ATTR_main_uv :: 2 -UB_VsParams :: 0 -IMG_tex :: 0 -SMP_smp :: 0 -Vsparams :: struct #align(16) { - using _: struct #packed { - mvp: Mat4, - }, -} -/* - #include - #include - - using namespace metal; - - struct VsParams - { - float4x4 mvp; - }; - - struct main0_out - { - float4 color [[user(locn0)]]; - float2 tex_coord [[user(locn1)]]; - float4 gl_Position [[position]]; - }; - - struct main0_in - { - float3 pos [[attribute(0)]]; - float4 col [[attribute(1)]]; - float2 uv [[attribute(2)]]; - }; - - vertex main0_out main0(main0_in in [[stage_in]], constant VsParams& _19 [[buffer(0)]]) - { - main0_out out = {}; - out.gl_Position = _19.mvp * float4(in.pos, 1.0); - out.color = in.col; - out.tex_coord = in.uv; - return out; - } - -*/ -@(private="file") -vs_source_metal_macos := [601]u8 { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x56, - 0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, - 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x74,0x65,0x78,0x5f,0x63,0x6f,0x6f,0x72,0x64,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72, - 0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a, - 0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30, - 0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33, - 0x20,0x70,0x6f,0x73,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65, - 0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x34,0x20,0x63,0x6f,0x6c,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, - 0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, - 0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74, - 0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e, - 0x73,0x74,0x61,0x6e,0x74,0x20,0x56,0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x26,0x20, - 0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d, - 0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2c,0x20,0x31,0x2e,0x30,0x29, - 0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75, - 0x74,0x2e,0x74,0x65,0x78,0x5f,0x63,0x6f,0x6f,0x72,0x64,0x20,0x3d,0x20,0x69,0x6e, - 0x2e,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, - 0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -} -/* - #include - #include - - using namespace metal; - - struct main0_out - { - float4 frag_color [[color(0)]]; - }; - - struct main0_in - { - float4 color [[user(locn0)]]; - float2 tex_coord [[user(locn1)]]; - }; - - fragment main0_out main0(main0_in in [[stage_in]], texture2d tex [[texture(0)]], sampler smp [[sampler(0)]]) - { - main0_out out = {}; - out.frag_color = tex.sample(smp, in.tex_coord) * in.color; - return out; - } - -*/ -@(private="file") -fs_source_metal_macos := [450]u8 { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, - 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x32,0x20,0x74,0x65,0x78,0x5f,0x63,0x6f,0x6f,0x72,0x64,0x20,0x5b,0x5b,0x75,0x73, - 0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a, - 0x0a,0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e, - 0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c, - 0x6f,0x61,0x74,0x3e,0x20,0x74,0x65,0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75, - 0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72, - 0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30, - 0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30, - 0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73, - 0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x5f,0x63,0x6f,0x6f,0x72,0x64, - 0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a, - 0x0a,0x00, -} -main_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc { - desc: sg.Shader_Desc - desc.label = "main_shader" - #partial switch backend { - case .METAL_MACOS: - desc.vertex_func.source = transmute(cstring)&vs_source_metal_macos - desc.vertex_func.entry = "main0" - desc.fragment_func.source = transmute(cstring)&fs_source_metal_macos - desc.fragment_func.entry = "main0" - desc.attrs[0].base_type = .FLOAT - desc.attrs[1].base_type = .FLOAT - desc.attrs[2].base_type = .FLOAT - desc.uniform_blocks[0].stage = .VERTEX - desc.uniform_blocks[0].layout = .STD140 - desc.uniform_blocks[0].size = 64 - desc.uniform_blocks[0].msl_buffer_n = 0 - desc.images[0].stage = .FRAGMENT - desc.images[0].multisampled = false - desc.images[0].image_type = ._2D - desc.images[0].sample_type = .FLOAT - desc.images[0].msl_texture_n = 0 - desc.samplers[0].stage = .FRAGMENT - desc.samplers[0].sampler_type = .FILTERING - desc.samplers[0].msl_sampler_n = 0 - desc.image_sampler_pairs[0].stage = .FRAGMENT - desc.image_sampler_pairs[0].image_slot = 0 - desc.image_sampler_pairs[0].sampler_slot = 0 - } - return desc -} diff --git a/shaders/out/cube.odin b/shaders/out/cube.odin new file mode 100644 index 0000000..d344294 --- /dev/null +++ b/shaders/out/cube.odin @@ -0,0 +1,162 @@ +package shaders +import sg "../../sokol/gfx" +/* + #version:1# (machine generated, don't edit!) + + Generated by sokol-shdc (https://github.com/floooh/sokol-tools) + + Cmdline: + sokol-shdc -i shaders/src/cube.glsl -o shaders/out/cube.odin -l metal_macos -f sokol_odin + + Overview: + ========= + Shader program: 'cube': + Get shader desc: cube_shader_desc(sg.query_backend()) + Vertex Shader: vs_cube + Fragment Shader: fs_cube + Attributes: + ATTR_cube_pos => 0 + Bindings: + Uniform block 'VsParamsCube': + Odin struct: Vsparamscube + Bind slot: UB_VsParamsCube => 0 +*/ +ATTR_cube_pos :: 0 +UB_VsParamsCube :: 0 +Vsparamscube :: struct #align(16) { + using _: struct #packed { + mvp: Mat4, + col: [4]f32, + }, +} +/* + #include + #include + + using namespace metal; + + struct VsParamsCube + { + float4x4 mvp; + float4 col; + }; + + struct main0_out + { + float4 color [[user(locn0)]]; + float4 gl_Position [[position]]; + }; + + struct main0_in + { + float3 pos [[attribute(0)]]; + }; + + vertex main0_out main0(main0_in in [[stage_in]], constant VsParamsCube& _19 [[buffer(0)]]) + { + main0_out out = {}; + out.gl_Position = _19.mvp * float4(in.pos, 1.0); + out.color = _19.col; + return out; + } + +*/ +@(private="file") +vs_cube_source_metal_macos := [496]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x56, + 0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x43,0x75,0x62,0x65,0x0a,0x7b,0x0a,0x20,0x20, + 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x3b,0x0a, + 0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30, + 0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, + 0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, + 0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, + 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, + 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20,0x70, + 0x6f,0x73,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30, + 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20, + 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28, + 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74, + 0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61, + 0x6e,0x74,0x20,0x56,0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x43,0x75,0x62,0x65,0x26, + 0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29, + 0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2c,0x20,0x31,0x2e,0x30, + 0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x63,0x6f,0x6c,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, + +} +/* + #include + #include + + using namespace metal; + + struct main0_out + { + float4 frag_color [[color(0)]]; + }; + + struct main0_in + { + float4 color [[user(locn0)]]; + }; + + fragment main0_out main0(main0_in in [[stage_in]]) + { + main0_out out = {}; + out.frag_color = in.color; + return out; + } + +*/ +@(private="file") +fs_cube_source_metal_macos := [315]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, + 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, + 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, + 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d, + 0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61, + 0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20, + 0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, + 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, + 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, + 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e, + 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +} +cube_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc { + desc: sg.Shader_Desc + desc.label = "cube_shader" + #partial switch backend { + case .METAL_MACOS: + desc.vertex_func.source = transmute(cstring)&vs_cube_source_metal_macos + desc.vertex_func.entry = "main0" + desc.fragment_func.source = transmute(cstring)&fs_cube_source_metal_macos + desc.fragment_func.entry = "main0" + desc.attrs[0].base_type = .FLOAT + desc.uniform_blocks[0].stage = .VERTEX + desc.uniform_blocks[0].layout = .STD140 + desc.uniform_blocks[0].size = 80 + desc.uniform_blocks[0].msl_buffer_n = 0 + } + return desc +} diff --git a/shaders/out/outline.odin b/shaders/out/outline.odin new file mode 100644 index 0000000..e1c0cd1 --- /dev/null +++ b/shaders/out/outline.odin @@ -0,0 +1,167 @@ +package shaders +import sg "../../sokol/gfx" +/* + #version:1# (machine generated, don't edit!) + + Generated by sokol-shdc (https://github.com/floooh/sokol-tools) + + Cmdline: + sokol-shdc -i shaders/src/outline.glsl -o shaders/out/outline.odin -l metal_macos -f sokol_odin + + Overview: + ========= + Shader program: 'outline': + Get shader desc: outline_shader_desc(sg.query_backend()) + Vertex Shader: vs_outline + Fragment Shader: fs_outline + Attributes: + ATTR_outline_pos => 0 + Bindings: + Uniform block 'VsParamsOutline': + Odin struct: Vsparamsoutline + Bind slot: UB_VsParamsOutline => 0 + Uniform block 'FsParamsOutline': + Odin struct: Fsparamsoutline + Bind slot: UB_FsParamsOutline => 1 +*/ +ATTR_outline_pos :: 0 +UB_VsParamsOutline :: 0 +UB_FsParamsOutline :: 1 +Vsparamsoutline :: struct #align(16) { + using _: struct #packed { + mvp: Mat4, + }, +} +Fsparamsoutline :: struct #align(16) { + using _: struct #packed { + col: [4]f32, + }, +} +/* + #include + #include + + using namespace metal; + + struct VsParamsOutline + { + float4x4 mvp; + }; + + struct main0_out + { + float4 gl_Position [[position]]; + }; + + struct main0_in + { + float3 pos [[attribute(0)]]; + }; + + vertex main0_out main0(main0_in in [[stage_in]], constant VsParamsOutline& _19 [[buffer(0)]]) + { + main0_out out = {}; + out.gl_Position = _19.mvp * float4(in.pos, 1.0); + return out; + } + +*/ +@(private="file") +vs_outline_source_metal_macos := [427]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x56, + 0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x4f,0x75,0x74,0x6c,0x69,0x6e,0x65,0x0a,0x7b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76, + 0x70,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, + 0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d, + 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20, + 0x70,0x6f,0x73,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28, + 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78, + 0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30, + 0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73, + 0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74, + 0x61,0x6e,0x74,0x20,0x56,0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x4f,0x75,0x74,0x6c, + 0x69,0x6e,0x65,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65, + 0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61, + 0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20, + 0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2c, + 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +} +/* + #include + #include + + using namespace metal; + + struct FsParamsOutline + { + float4 col; + }; + + struct main0_out + { + float4 frag_color [[color(0)]]; + }; + + fragment main0_out main0(constant FsParamsOutline& _12 [[buffer(0)]]) + { + main0_out out = {}; + out.frag_color = _12.col; + return out; + } + +*/ +@(private="file") +fs_outline_source_metal_macos := [322]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x46, + 0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x4f,0x75,0x74,0x6c,0x69,0x6e,0x65,0x0a,0x7b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x3b, + 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b, + 0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, + 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, + 0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e, + 0x74,0x20,0x46,0x73,0x50,0x61,0x72,0x61,0x6d,0x73,0x4f,0x75,0x74,0x6c,0x69,0x6e, + 0x65,0x26,0x20,0x5f,0x31,0x32,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28, + 0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x20,0x3d,0x20,0x5f,0x31,0x32,0x2e,0x63,0x6f,0x6c,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a, + 0x0a,0x00, +} +outline_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc { + desc: sg.Shader_Desc + desc.label = "outline_shader" + #partial switch backend { + case .METAL_MACOS: + desc.vertex_func.source = transmute(cstring)&vs_outline_source_metal_macos + desc.vertex_func.entry = "main0" + desc.fragment_func.source = transmute(cstring)&fs_outline_source_metal_macos + desc.fragment_func.entry = "main0" + desc.attrs[0].base_type = .FLOAT + desc.uniform_blocks[0].stage = .VERTEX + desc.uniform_blocks[0].layout = .STD140 + desc.uniform_blocks[0].size = 64 + desc.uniform_blocks[0].msl_buffer_n = 0 + desc.uniform_blocks[1].stage = .FRAGMENT + desc.uniform_blocks[1].layout = .STD140 + desc.uniform_blocks[1].size = 16 + desc.uniform_blocks[1].msl_buffer_n = 0 + } + return desc +} diff --git a/shaders/out/types.odin b/shaders/out/types.odin new file mode 100644 index 0000000..992ab67 --- /dev/null +++ b/shaders/out/types.odin @@ -0,0 +1,7 @@ +package shaders + +Mat4 :: matrix[4, 4]f32 + +Vec2 :: [2]f32 +Vec3 :: [3]f32 +Vec4 :: [4]f32 diff --git a/shaders/src/cube.glsl b/shaders/src/cube.glsl new file mode 100644 index 0000000..c31b83e --- /dev/null +++ b/shaders/src/cube.glsl @@ -0,0 +1,34 @@ +@header package shaders +@header import sg "../../sokol/gfx" + +@ctype mat4 Mat4 + +@vs vs_cube +in vec3 pos; + +layout(binding = 0) uniform VsParamsCube { + mat4 mvp; + vec4 col; +}; + +out vec4 color; + +void main() { + gl_Position = mvp * vec4(pos, 1); + color = col; +} + +@end + +@fs fs_cube +in vec4 color; + +out vec4 frag_color; + +void main() { + frag_color = color; +} + +@end + +@program cube vs_cube fs_cube diff --git a/shaders/src/outline.glsl b/shaders/src/outline.glsl new file mode 100644 index 0000000..22feddb --- /dev/null +++ b/shaders/src/outline.glsl @@ -0,0 +1,30 @@ +@header package shaders +@header import sg "../../sokol/gfx" + +@ctype mat4 Mat4 + +@vs vs_outline +in vec3 pos; + +layout(binding = 0) uniform VsParamsOutline { + mat4 mvp; +}; + +void main() { + gl_Position = mvp * vec4(pos, 1); +} +@end + +@fs fs_outline +layout(binding = 1) uniform FsParamsOutline { + vec4 col; +}; + +out vec4 frag_color; + +void main() { + frag_color = col; +} +@end + +@program outline vs_outline fs_outline