Compare commits

..

1 commit

Author SHA1 Message Date
05ba2a60d6 Add render system 2025-08-24 22:51:30 +02:00
32 changed files with 678 additions and 1105 deletions

View file

@ -1,25 +1,17 @@
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
./sokol-shdc -i shaders/src/shader.glsl -o shaders/out/shader.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 .

View file

@ -1,5 +0,0 @@
# 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)

View file

@ -1,28 +0,0 @@
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 }

View file

@ -1,47 +0,0 @@
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
}
}

View file

@ -1,88 +1,66 @@
#+private
package ecs
import "core:log"
ComponentManager :: struct {
component_ids: map[typeid]ComponentID,
component_types: map[typeid]ComponentType,
component_pools: map[typeid]^ComponentPool(any),
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)),
next_component_type: ComponentType,
}
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_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_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_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.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_pool_insert_data(T, component_pool, entity_id, component)
}
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_pool_remove_data(T, component_pool, entity_id)
}
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(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_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_destroy_entity :: proc(component_manager: ^ComponentManager, entity_id: EntityID) {
for Component, component_pool in component_manager.component_pools {
component_manager.component_pool_destroy_entity_cbs[Component](component_pool, entity_id)
for _, component_pool in component_manager.component_pools {
component_pool_destroy_entity(component_pool, entity_id)
}
}
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)
component_manager_destroy :: proc(component_manager: ^ComponentManager) {
for _, &component_pool in component_manager.component_pools {
component_pool_destroy(component_pool)
free(component_pool)
}
delete(component_manager.component_pools)
delete(component_manager.component_ids)
delete(component_manager.component_pool_destroy_entity_cbs)
delete(component_manager.component_pool_delete_cbs)
delete(component_manager.component_types)
}

View file

@ -1,23 +1,26 @@
#+private
package ecs
import "core:log"
ComponentPool :: struct(Component: typeid) {
data: []Component,
ComponentPool :: struct($T: typeid) {
data: []T,
entity_to_index: map[EntityID]uintptr,
index_to_entity: map[uintptr]EntityID,
size: uintptr,
}
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_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,
}
component_pool_insert_data :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID, component: Component) {
return component_pool
}
component_pool_insert_data :: proc($T: typeid, component_pool: ^ComponentPool(T), entity_id: EntityID, component: T) {
log.assertf(entity_id not_in component_pool.entity_to_index, "Component already added to entity")
new_idx := component_pool.size
@ -28,7 +31,7 @@ component_pool_insert_data :: proc(component_pool: ^ComponentPool($Component), e
component_pool.size += 1
}
component_pool_remove_data :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID) {
component_pool_remove_data :: proc(component_pool: ^ComponentPool(any), 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]
@ -45,21 +48,21 @@ component_pool_remove_data :: proc(component_pool: ^ComponentPool($Component), e
component_pool.size -= 1
}
component_pool_get :: proc(component_pool: ^ComponentPool($Component), entity_id: EntityID) -> ^Component {
component_pool_get :: proc($T: typeid, component_pool: ^ComponentPool(T), entity_id: EntityID) -> ^T {
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($Component), entity_id: EntityID) {
component_pool_destroy_entity :: proc(component_pool: ^ComponentPool(any), entity_id: EntityID) {
if entity_id in component_pool.entity_to_index {
component_pool_remove_data(component_pool, entity_id)
}
}
component_pool_delete :: proc(component_pool: ^ComponentPool($Component)) {
delete(component_pool.data)
component_pool_destroy :: proc(component_pool: ^ComponentPool(any)) {
delete(component_pool.entity_to_index)
delete(component_pool.index_to_entity)
delete(component_pool.data)
}

View file

@ -1,6 +1,5 @@
package ecs
import sa "../sokol/app"
import sg "../sokol/gfx"
Mat4 :: matrix[4, 4]f32
@ -9,52 +8,38 @@ Vec2 :: [2]f32
Vec3 :: [3]f32
Vec4 :: [4]f32
GravityComponent :: struct {
Gravity :: struct {
force: Vec3
}
RigidBodyComponent :: struct {
RigidBody :: struct {
velocity: Vec3,
acceleration: Vec3,
}
TransformComponent :: struct {
Transform :: struct {
position: Vec3,
rotation: Vec3,
scale: Vec3,
}
ColorComponent :: struct {
Color :: struct {
color: Vec4,
}
MeshID :: enum {
Cube,
Mesh :: struct {
vertex_buffer: sg.Buffer,
index_buffer: sg.Buffer,
}
MeshComponent :: struct {
mesh_id: MeshID
Material :: struct {
shader: sg.Shader,
image: sg.Image,
sampler: sg.Sampler,
}
MaterialID :: enum {
Cube,
Outline,
}
MaterialComponent :: struct {
material_id: MaterialID
}
CameraComponent :: struct {
Camera :: struct {
position: Vec3,
target: Vec3,
look: Vec2,
look_sensitivity: f32,
movement_speed: f32,
}
InputComponent :: struct {
mouse_movement: Vec2,
key_down: #sparse[sa.Keycode]bool,
look: Vec2
}

View file

@ -6,4 +6,4 @@ COMPONENT_MAX :: 32
ID :: u32
EntityID :: ID
ComponentID :: u16
ComponentType :: u8

View file

@ -1,70 +1,82 @@
package ecs
Coordinator :: struct {
component_manager: ComponentManager,
entity_manager: EntityManager,
system_manager: SystemManager,
component_manager: ^ComponentManager,
entity_manager: ^EntityManager,
system_manager: ^SystemManager,
}
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 :: 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_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(coordinator: ^Coordinator, $Component: typeid) {
component_manager_register_component(Component, &coordinator.component_manager)
coordinator_register_component :: proc($T: typeid, coordinator: ^Coordinator) {
component_manager_register_component(T, coordinator.component_manager)
}
coordinator_add_component :: proc(coordinator: ^Coordinator, component: $Component, entity_id: EntityID) {
component_manager_add_component(&coordinator.component_manager, component, entity_id)
coordinator_add_component :: proc($T: typeid, coordinator: ^Coordinator, entity_id: EntityID, component: T) {
component_manager_add_component(T, coordinator.component_manager, entity_id, component)
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)
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)
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(coordinator: ^Coordinator, $Component: typeid, entity_id: EntityID) {
component_manager_remove_component(&coordinator.component_manager, Component, entity_id)
coordinator_remove_component :: proc($T: typeid, coordinator: ^Coordinator, entity_id: EntityID) {
component_manager_remove_component(T, coordinator.component_manager, entity_id)
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)
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)
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(coordinator: ^Coordinator, $Component: typeid, entity_id: EntityID) -> ^Component {
return component_manager_get_component(&coordinator.component_manager, Component, entity_id)
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_id :: proc(coordinator: ^Coordinator, $Component: typeid) -> ComponentID {
return component_manager_get_component_id(&coordinator.component_manager, Component)
coordinator_get_component_type :: proc($T: typeid, coordinator: ^Coordinator) -> ComponentType {
return component_manager_get_component_type(T, coordinator.component_manager)
}
coordinator_register_system :: proc(coordinator: ^Coordinator, $System: typeid) -> ^System {
return system_manager_register_system(&coordinator.system_manager, System)
coordinator_register_system :: proc($T: typeid, coordinator: ^Coordinator) -> ^T {
return system_manager_register_system(T, coordinator.system_manager)
}
coordinator_set_system_signature :: proc(coordinator: ^Coordinator, $System: typeid, signature: Signature) {
system_manager_set_signature(&coordinator.system_manager, System, signature)
coordinator_set_system_signature :: proc($T: typeid, coordinator: ^Coordinator, signature: Signature) {
system_manager_set_signature(T, coordinator.system_manager, signature)
}
coordinator_delete :: proc(coordinator: ^Coordinator) {
component_manager_delete(&coordinator.component_manager)
entity_manager_delete(&coordinator.entity_manager)
system_manager_delete(&coordinator.system_manager)
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)
}

View file

@ -1,4 +1,3 @@
#+private
package ecs
import "core:log"
@ -10,12 +9,15 @@ EntityManager :: struct {
living_entity_count: u32,
}
entity_manager_init :: proc(entity_manager: ^EntityManager) {
entity_manager_create :: proc() -> EntityManager {
entity_manager := EntityManager{living_entity_count = 0}
queue.init(&entity_manager.available_entities)
for entity_id in 0..<ENTITY_MAX {
queue.push_back(&entity_manager.available_entities, cast(EntityID)entity_id)
}
return entity_manager
}
entity_manager_create_entity :: proc(entity_manager: ^EntityManager) -> EntityID {
@ -47,6 +49,6 @@ entity_manager_get_signature :: proc(entity_manager: ^EntityManager, entity_id:
return entity_manager.signatures[entity_id]
}
entity_manager_delete :: proc(entity_manager: ^EntityManager) {
entity_manager_destroy :: proc(entity_manager: ^EntityManager) {
queue.destroy(&entity_manager.available_entities)
}

View file

@ -1,32 +0,0 @@
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 }
}
}

View file

@ -1,31 +1,16 @@
package ecs
import "core:log"
import program_config "../config"
PhysicsSystem :: struct {
using _: SystemBase,
using base: 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_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)
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)
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)
}
}

View file

@ -17,44 +17,49 @@ 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,
uv: Vec2,
}
RenderSystem :: struct {
using _: SystemBase,
user_entity: EntityID,
using base: SystemBase,
materials: map[MaterialID]Material,
meshes : map[MeshID]Mesh,
shader: sg.Shader,
pipeline: sg.Pipeline,
vertex_buffer: sg.Buffer,
index_buffer: sg.Buffer,
image: sg.Image,
sampler: sg.Sampler,
camera: struct {
pos: Vec3,
target: Vec3,
look: Vec2,
},
}
@(private="file")
init_outline_material :: proc(render_system: ^RenderSystem) {
shader := sg.make_shader(shaders.outline_shader_desc(sg.query_backend()))
init_render_system :: proc(render_system: ^RenderSystem) {
default_context := runtime.default_context()
sg.setup({
environment = sh.glue_environment(),
allocator = sg.Allocator(sh.allocator(&default_context)),
logger = sg.Logger(sh.logger(&default_context)),
})
shader := sg.make_shader(shaders.main_shader_desc(sg.query_backend()))
pipeline := sg.make_pipeline({
shader = shader,
layout = {
attrs = {
shaders.ATTR_outline_pos = { format = .FLOAT3 },
shaders.ATTR_main_pos = { format = .FLOAT3 },
shaders.ATTR_main_uv = { format = .FLOAT2 },
},
},
index_type = .UINT16,
@ -67,247 +72,187 @@ init_outline_material :: proc(render_system: ^RenderSystem) {
bias_slope_scale = 1.0,
compare = .LESS_EQUAL,
},
sample_count = 4,
})
render_system.materials[.Outline] = Material{
shader = shader,
pipeline = pipeline,
}
}
vertices := []VertexData {
{ pos = { -0.5, -0.5, 0.5 }, uv = { 0, 0 } },
{ pos = { 0.5, -0.5, 0.5 }, uv = { 1, 0 } },
{ pos = { 0.5, 0.5, 0.5 }, uv = { 1, 1 } },
{ pos = { -0.5, 0.5, 0.5 }, uv = { 0, 1 } },
@(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,
})
{ pos = { -0.5, -0.5, -0.5 }, uv = { 1, 0 } },
{ pos = { 0.5, -0.5, -0.5 }, uv = { 0, 0 } },
{ pos = { 0.5, 0.5, -0.5 }, uv = { 0, 1 } },
{ pos = { -0.5, 0.5, -0.5 }, uv = { 1, 1 } },
render_system.materials[.Cube] = Material{
shader = shader,
pipeline = pipeline,
}
}
{ pos = { -0.5, 0.5, 0.5 }, uv = { 0, 0 } },
{ pos = { 0.5, 0.5, 0.5 }, uv = { 1, 0 } },
{ pos = { 0.5, 0.5, -0.5 }, uv = { 1, 1 } },
{ pos = { -0.5, 0.5, -0.5 }, uv = { 0, 1 } },
@(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 }, uv = { 0, 0 } },
{ pos = { 0.5, -0.5, 0.5 }, uv = { 1, 0 } },
{ pos = { 0.5, -0.5, -0.5 }, uv = { 1, 1 } },
{ pos = { -0.5, -0.5, -0.5 }, uv = { 0, 1 } },
{ 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 }, uv = { 0, 0 } },
{ pos = { 0.5, -0.5, -0.5 }, uv = { 1, 0 } },
{ pos = { 0.5, 0.5, -0.5 }, uv = { 1, 1 } },
{ pos = { 0.5, 0.5, 0.5 }, uv = { 0, 1 } },
{ 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 }, uv = { 1, 0 } },
{ pos = { -0.5, -0.5, -0.5 }, uv = { 0, 0 } },
{ pos = { -0.5, 0.5, -0.5 }, uv = { 0, 1 } },
{ pos = { -0.5, 0.5, 0.5 }, uv = { 1, 1 } },
}
vertex_buffer := sg.make_buffer({
data = sg_range(cube_vertices)
data = sg_range(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,
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,
}
index_buffer := sg.make_buffer({
usage = { index_buffer = true },
data = sg_range(cube_indices),
data = sg_range(indices),
})
render_system.meshes[.Cube] = Mesh{
vertex_buffer = vertex_buffer,
index_buffer = index_buffer,
w, h: i32
pixels := stbi.load("res/white.png", &w, &h, nil, 4)
assert(pixels != nil)
defer(stbi.image_free(pixels))
image := sg.make_image({
width = w,
height = h,
pixel_format = .RGBA8,
data = {
subimage = {
0 = {
0 = {
ptr = pixels,
size = uint(w * h * 4)
}
}
}
}
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
sampler := sg.make_sampler({})
init_cube_mesh(render_system)
init_cube_material(render_system)
init_outline_material(render_system)
render_system.sampler = sampler
render_system.shader = shader
render_system.image = image
render_system.pipeline = pipeline
render_system.vertex_buffer = vertex_buffer
render_system.index_buffer = index_buffer
render_system.camera = {
pos = { 30, 0, 60 },
target = { 0, 0, 1 },
}
}
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)
delete_render_system :: proc(render_system: ^RenderSystem) {
sg.destroy_buffer(render_system.index_buffer)
sg.destroy_buffer(render_system.vertex_buffer)
sg.destroy_image(render_system.image)
sg.destroy_sampler(render_system.sampler)
sg.destroy_pipeline(render_system.pipeline)
sg.destroy_shader(render_system.shader)
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) {
camera := coordinator_get_component(coordinator, CameraComponent, render_system.user_entity)
render_system_update :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, dt: f32, key_down: #sparse[sa.Keycode]bool, mouse_move: Vec2) {
update_camera(render_system, dt, key_down, mouse_move)
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 } )
view := linalg.matrix4_look_at_f32(render_system.camera.pos, render_system.camera.target, { 0, 1, 0 } )
sg.begin_pass({ swapchain = sh.glue_swapchain() })
sg.apply_pipeline(render_system.pipeline)
sg.apply_bindings({
vertex_buffers = { 0 = render_system.vertex_buffer },
index_buffer = render_system.index_buffer,
images = { shaders.IMG_tex = render_system.image },
samplers = { shaders.SMP_smp = render_system.sampler },
})
for entity in render_system.entities {
transform := coordinator_get_component(Transform, coordinator, entity)
color := coordinator_get_component(Color, coordinator, entity)
pos_mat := linalg.matrix4_translate_f32(transform.position)
rot_mat := linalg.matrix4_from_yaw_pitch_roll_f32(transform.rotation.y, transform.rotation.x, transform.rotation.z)
model := pos_mat * rot_mat
sg.apply_uniforms(shaders.UB_VsParams, sg_range(&shaders.Vsparams{
mvp = proj * view * model,
col = color.color
}))
sg.draw(0, 36, 1)
}
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")
@(private)
update_camera :: proc(render_system: ^RenderSystem, dt: f32, key_down: #sparse[sa.Keycode]bool, mouse_move: Vec2) {
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
render_system.camera.look += look_input
render_system.camera.look.x = math.wrap(render_system.camera.look.x, 360)
render_system.camera.look.y = math.clamp(render_system.camera.look.y, -89.5, 89.5)
look_mat := linalg.matrix4_from_yaw_pitch_roll_f32(
linalg.to_radians(render_system.camera.look.x),
linalg.to_radians(render_system.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
render_system.camera.pos += motion
render_system.camera.target = render_system.camera.pos + forward
}
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),
@ -315,7 +260,6 @@ 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,

View file

@ -2,15 +2,15 @@ package ecs
Signature :: bit_set[0..<COMPONENT_MAX]
signature_make :: proc() -> Signature {
signature_create :: proc() -> Signature {
return Signature{}
}
signature_set :: proc(signature: ^Signature, type: ComponentID) {
signature_set :: proc(signature: ^Signature, type: ComponentType) {
signature^ += {cast(int)type}
}
signature_unset :: proc(signature: ^Signature, type: ComponentID) {
signature_unset :: proc(signature: ^Signature, type: ComponentType) {
signature^ -= {cast(int)type}
}

View file

@ -1,14 +1,10 @@
#+private
package ecs
import "base:intrinsics"
import "core:log"
@(private = "file")
EntitySet :: map[EntityID]struct{}
SystemBase :: struct {
entities: EntitySet
entities: map[EntityID]struct{}, // Treat as set
}
SystemManager :: struct {
@ -16,30 +12,29 @@ SystemManager :: struct {
systems: map[typeid]^SystemBase
}
system_base_init :: proc(system_base: ^SystemBase) {
system_base.entities = make(EntitySet, context.allocator)
system_manager_create :: proc() -> SystemManager {
system_manager := SystemManager{
signatures = make(map[typeid]Signature, context.allocator),
systems = make(map[typeid]^SystemBase, context.allocator),
}
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)
return system_manager
}
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_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 := new(System, context.allocator)
system_base_init(system)
system_manager.systems[System] = system
system := new(T, context.allocator)
system.entities = make(map[EntityID]struct{})
system_manager.systems[T] = system
return system
}
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_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_destroy_entity :: proc(system_manager: ^SystemManager, entity_id: EntityID) {
@ -59,7 +54,7 @@ system_manager_change_entity_signature :: proc(system_manager: ^SystemManager, e
}
}
system_manager_delete :: proc(system_manager: ^SystemManager) {
system_manager_destroy :: proc(system_manager: ^SystemManager) {
for _, system in system_manager.systems {
delete(system.entities)
free(system)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

238
main.odin
View file

@ -18,47 +18,42 @@ 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 "ecs"
import program_config "config"
Vec2 :: ecs.Vec2
Vec3 :: ecs.Vec3
Vec4 :: ecs.Vec4
Vec2 :: [2]f32
Vec3 :: [3]f32
Vec4 :: [4]f32
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,
entities: []ecs.EntityID,
}
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)
default_context = context
sa.run({
window_title = program_config.WINDOW_TITLE,
window_title = "Ecs Test",
allocator = sa.Allocator(sh.allocator(&default_context)),
logger = sg.Logger( { func = sl.func } ),
sample_count = 4,
logger = sa.Logger(sh.logger(&default_context)),
init_cb = init_cb,
frame_cb = frame_cb,
@ -74,7 +69,7 @@ init_cb :: proc "c" () {
sa.lock_mouse(true)
g = new(Globals)
ecs.coordinator_init(&g.coordinator)
g.coordinator = ecs.coordinator_create()
create_scene()
}
@ -82,175 +77,122 @@ init_cb :: proc "c" () {
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()
if key_down[.ESCAPE] {
sa.quit()
return
}
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)
dt := f32(sa.frame_duration())
ecs.input_system_mouse_reset(g.input_system, &g.coordinator)
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.render_system_delete(g.render_system, &g.coordinator)
ecs.delete_render_system(g.render_system)
ecs.coordinator_delete(&g.coordinator)
delete(g.entities)
ecs.coordinator_destroy(&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)
#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_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(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)
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(ecs.PhysicsSystem, &g.coordinator)
g.render_system = ecs.coordinator_register_system(ecs.RenderSystem, &g.coordinator)
ecs.init_render_system(g.render_system)
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)
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)
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)
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.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
)
g.entities = make([]ecs.EntityID, ecs.ENTITY_MAX)
for &entity in g.entities {
entity = ecs.coordinator_create_entity(&g.coordinator)
ecs.coordinator_add_component(
coordinator,
ecs.InputComponent{
key_down = {},
mouse_movement = Vec2{ 0, 0 }
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)),
},
user_entity
)
ecs.render_system_init(g.render_system, user_entity)
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) {
clean := true
if len(track.allocation_map) > 0 {
fmt.eprintfln("=== %v allocations not freed: ===", len(track.allocation_map))
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)
}
clean = false
}
if len(track.bad_free_array) > 0 {
fmt.eprintfln("=== %v incorrect frees: ===", len(track.bad_free_array))
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 clean do fmt.printfln("=== No memory leaked ===")
mem.tracking_allocator_destroy(track)
}

BIN
res/texture_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/texture_green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/texture_orange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/texture_pink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/texture_purple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/texture_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

BIN
res/texture_yellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
res/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

View file

@ -1,162 +0,0 @@
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 <metal_stdlib>
#include <simd/simd.h>
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 <metal_stdlib>
#include <simd/simd.h>
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
}

View file

@ -1,167 +0,0 @@
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 <metal_stdlib>
#include <simd/simd.h>
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 <metal_stdlib>
#include <simd/simd.h>
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
}

205
shaders/out/shader.odin Normal file
View file

@ -0,0 +1,205 @@
package shader
import sg "../../sokol/gfx"
import ecs "../../types"
/*
#version:1# (machine generated, don't edit!)
Generated by sokol-shdc (https://github.com/floooh/sokol-tools)
Cmdline:
sokol-shdc -i shaders/src/shader.glsl -o shaders/out/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_uv => 1
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_uv :: 1
UB_VsParams :: 0
IMG_tex :: 0
SMP_smp :: 0
Vsparams :: struct #align(16) {
using _: struct #packed {
mvp: ecs.Mat4,
col: [4]f32,
},
}
/*
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct VsParams
{
float4x4 mvp;
float4 col;
};
struct main0_out
{
float4 color [[user(locn0)]];
float2 tex_coord [[user(locn1)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float3 pos [[attribute(0)]];
float2 uv [[attribute(1)]];
};
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 = _19.col;
out.tex_coord = in.uv;
return out;
}
*/
@(private="file")
vs_source_metal_macos := [585]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,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,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,
0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,
0x28,0x31,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,0x5f,0x31,0x39,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 <metal_stdlib>
#include <simd/simd.h>
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<float> 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.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
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
}

View file

@ -1,7 +0,0 @@
package shaders
Mat4 :: matrix[4, 4]f32
Vec2 :: [2]f32
Vec3 :: [3]f32
Vec4 :: [4]f32

View file

@ -1,34 +0,0 @@
@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

View file

@ -1,30 +0,0 @@
@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

42
shaders/src/shader.glsl Normal file
View file

@ -0,0 +1,42 @@
@header package shader
@header import sg "../../sokol/gfx"
@header import ecs "../../types"
@ctype mat4 ecs.Mat4
@vs vs
in vec3 pos;
in vec2 uv;
layout(binding = 0) uniform VsParams {
mat4 mvp;
vec4 col;
};
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