Add render system

This commit is contained in:
Hugo Mårdbrink 2025-08-24 22:51:30 +02:00
parent af76df6a81
commit 05ba2a60d6
8 changed files with 395 additions and 330 deletions

329
main.odin
View file

@ -13,12 +13,12 @@ import "core:path/filepath"
import "core:math"
import "core:math/linalg"
import "core:os"
import "core:math/rand"
import stbi "vendor:stb/image"
import sa "sokol/app"
import sh "sokol/helpers"
import sg "sokol/gfx"
import "ecs"
@ -26,37 +26,11 @@ 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,
}
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,
physics_system: ^ecs.PhysicsSystem,
render_system: ^ecs.RenderSystem,
entities: []ecs.EntityID,
}
g: ^Globals
@ -86,131 +60,18 @@ main :: proc() {
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)
g.coordinator = ecs.coordinator_create()
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" () {
@ -221,103 +82,22 @@ frame_cb:: proc "c" () {
return
}
start_time := time.now()
//ecs.physics_system_update(g.scene.physics_system, &g.coordinator, g.dt) // seg fault
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 } )
dt := f32(sa.frame_duration())
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()
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 = {}
}
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
}
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.delete_render_system(g.render_system)
delete(g.entities)
ecs.coordinator_destroy(&g.coordinator)
free(g)
sg.shutdown()
}
event_cb :: proc "c" (event: ^sa.Event) {
@ -333,35 +113,41 @@ event_cb :: proc "c" (event: ^sa.Event) {
}
}
create_scene :: proc(coordinator: ^ecs.Coordinator) -> Scene {
scene := Scene{}
ecs.coordinator_register_component(ecs.Gravity, coordinator)
ecs.coordinator_register_component(ecs.RigidBody, coordinator)
ecs.coordinator_register_component(ecs.Transform, coordinator)
create_scene :: proc() {
ecs.coordinator_register_component(ecs.Gravity, &g.coordinator)
ecs.coordinator_register_component(ecs.RigidBody, &g.coordinator)
ecs.coordinator_register_component(ecs.Transform, &g.coordinator)
ecs.coordinator_register_component(ecs.Color, &g.coordinator)
scene.physics_system = ecs.coordinator_register_system(ecs.PhysicsSystem, coordinator)
g.physics_system = ecs.coordinator_register_system(ecs.PhysicsSystem, &g.coordinator)
g.render_system = ecs.coordinator_register_system(ecs.RenderSystem, &g.coordinator)
ecs.init_render_system(g.render_system)
signature := ecs.signature_create()
ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Gravity, 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)
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)
scene.entities = make([]ecs.EntityID, ecs.ENTITY_MAX)
for &entity in scene.entities {
entity = ecs.coordinator_create_entity(coordinator)
signature = ecs.signature_create()
ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Transform, &g.coordinator))
ecs.signature_set(&signature, ecs.coordinator_get_component_type(ecs.Color, &g.coordinator))
ecs.coordinator_set_system_signature(ecs.RenderSystem, &g.coordinator, signature)
g.entities = make([]ecs.EntityID, ecs.ENTITY_MAX)
for &entity in g.entities {
entity = ecs.coordinator_create_entity(&g.coordinator)
ecs.coordinator_add_component(
ecs.Gravity,
coordinator,
&g.coordinator,
entity,
ecs.Gravity{
ecs.Vec3{0.0, -9.82, 0.0}
ecs.Vec3{0.0, -2.82, 0.0}
})
ecs.coordinator_add_component(
ecs.RigidBody,
coordinator,
&g.coordinator,
entity,
ecs.RigidBody{
velocity = ecs.Vec3{0.0, 0.0, 0.0},
@ -369,35 +155,30 @@ create_scene :: proc(coordinator: ^ecs.Coordinator) -> Scene {
})
ecs.coordinator_add_component(
ecs.Transform,
coordinator,
&g.coordinator,
entity,
ecs.Transform{
position = ecs.Vec3{0.0, 0.0, 0.0},
position = Vec3{
f32(rand.int_max(50)),
f32(rand.int_max(10)),
f32(rand.int_max(50)),
},
rotation = ecs.Vec3{0.0, 0.0, 0.0},
scale = ecs.Vec3{1.0, 1.0, 1.0},
})
ecs.coordinator_add_component(
ecs.Color,
&g.coordinator,
entity,
ecs.Color{
color = Vec4{
rand.float32_uniform(0,1),
rand.float32_uniform(0,1),
rand.float32_uniform(0,1),
rand.float32_uniform(0,1),
},
})
}
return scene
}
sg_range :: proc {
sg_range_from_slice,
sg_range_from_struct,
}
sg_range_from_slice :: proc(s: []$T) -> sg.Range {
return {
ptr = raw_data(s),
size = len(s) * size_of(T),
}
}
sg_range_from_struct :: proc(s: ^$T) -> sg.Range where intrinsics.type_is_struct(T) {
return {
ptr = s,
size = size_of(T),
}
}
reset_tracking_allocator :: proc(track: ^mem.Tracking_Allocator) {