qt_pool_buffer : [] QuadTree(^Body);
qt_pool_allocator : alloc.pool.PoolAllocator(QuadTree(^Body));
qt_body_allocator : Allocator;
+
+ thread_data : [] Thread_Data;
+ threads : [] thread.Thread;
+}
+
+Thread_Data :: struct {
+ id : i32;
+ state: ^Sim_State;
}
-#thread_local state: Sim_State;
+body_program : gl.GLProgram;
+body_buffer : gl.GLBuffer;
+circle_mesh : gl.GLVertexArrayObject;
+thread_sync_barrier : sync.Barrier;
+frame_sync_sema : sync.Semaphore;
+global_dt := 0.016f;
+keys: Set(i32);
+
+#thread_local state: ^Sim_State;
sim_state_init :: (state: ^Sim_State) {
array.init(^state.bodies);
state.qt_body_allocator = alloc.pool.make_allocator(^state.qt_pool_allocator);
state.qt_bodies->init(AABB.{ -2000, -2000, 4000, 4000 });
-}
-body_program : gl.GLProgram;
-body_buffer : gl.GLBuffer;
-circle_mesh : gl.GLVertexArrayObject;
+ keys->init();
+
+ sync.barrier_init(^thread_sync_barrier, global_settings.thread_count);
+ sync.semaphore_init(^frame_sync_sema, 0);
+
+ memory.alloc_slice(^state.threads, global_settings.thread_count);
+ memory.alloc_slice(^state.thread_data, global_settings.thread_count);
+
+ for i: global_settings.thread_count {
+ state.thread_data[i] = .{ i, state };
+ thread.spawn(^state.threads[i], ^state.thread_data[i], thread_processing);
+ }
+}
create_circle_mesh :: () -> gl.GLVertexArrayObject {
vao := gl.createVertexArray();
return vao;
}
+paused := false;
handle_event :: (ev) => {
switch ev.kind {
case .KeyDown {
- switch ev.keyboard.keycode {
- case 38 do state.camera.offset.y -= 6;
- case 40 do state.camera.offset.y += 6;
- case 39 do state.camera.offset.x += 6;
- case 37 do state.camera.offset.x -= 6;
- case 65 do state.camera.scale /= 1.02;
- case 81 do state.camera.scale *= 1.02;
- }
+ keys->insert(ev.keyboard.keycode);
+ }
+
+ case .KeyUp {
+ if ev.keyboard.keycode == #char "p" do paused = !paused;
+ keys->remove(ev.keyboard.keycode);
}
case .Resize {
}
update :: (dt: f32) {
- state.qt_bodies->init(.{ -2000, -2000, 4000, 4000 });
- state.qt_pool_allocator = alloc.pool.make(state.qt_pool_buffer);
+ global_dt = dt;
+
+ if keys->has(38) do state.camera.offset.y -= 6;
+ if keys->has(40) do state.camera.offset.y += 6;
+ if keys->has(39) do state.camera.offset.x += 6;
+ if keys->has(37) do state.camera.offset.x -= 6;
+ if keys->has(65) do state.camera.scale /= 1.02;
+ if keys->has(81) do state.camera.scale *= 1.02;
+}
- for ^it: state.bodies {
- state.qt_bodies->insert(it, state.qt_body_allocator);
- }
+update_bodies_partial :: (index: i32) {
+ low := index * (global_settings.body_count / global_settings.thread_count);
+ high := (index + 1) * (global_settings.body_count / global_settings.thread_count);
- for i: state.bodies.count {
- body_accumulate_move(^state.bodies[i], ^state.qt_bodies, dt);
- }
+ for i: low .. high do body_accumulate_move(^state.bodies[i], ^state.qt_bodies, global_dt);
+ sync.barrier_wait(^thread_sync_barrier);
+ for i: low .. high do body_apply_move(^state.bodies[i], global_dt);
+}
+
+thread_processing :: (td: ^Thread_Data) {
+ thread_id := td.id;
+ state = td.state;
- for i: state.bodies.count {
- body_apply_move(^state.bodies[i], dt);
+ while true {
+ if thread_id == 0 {
+ state.qt_bodies->init(.{ -2000, -2000, 4000, 4000 });
+ state.qt_pool_allocator = alloc.pool.make(state.qt_pool_buffer);
+
+ for ^it: state.bodies {
+ state.qt_bodies->insert(it, state.qt_body_allocator);
+ }
+ }
+
+ sync.barrier_wait(^thread_sync_barrier);
+ update_bodies_partial(thread_id);
+ sync.barrier_wait(^thread_sync_barrier);
+
+ sync.semaphore_wait(^frame_sync_sema);
}
}
gl.bindVertexArray(circle_mesh);
gl.drawElementsInstanced(gl.TRIANGLE_FAN, 12, gl.UNSIGNED_BYTE, 0, state.bodies.count);
gl.bindVertexArray(-1);
+
+ sync.semaphore_post(^frame_sync_sema, 0 if paused else global_settings.thread_count);
}
main :: (args) => {
planet_colors := cast(^f32) global_settings.body_color.data;
gl.uniform3fv(planet_colors_loc, .{ ~~planet_colors, global_settings.body_type_count });
- sim_state_init(^state);
+ state = make(Sim_State);
+ sim_state_init(state);
gl.bindVertexArray(circle_mesh);
body_buffer = gl.createBuffer();
x, y: f32;
}
-#operator+ (a, b: V2f) => V2f.{ a.x + b.x, a.y + b.y };
-#operator- (a, b: V2f) => V2f.{ a.x - b.x, a.y - b.y };
-#operator* (a: V2f, s: f32) => V2f.{ a.x * s, a.y * s };
+#operator+ macro (a, b: V2f) => V2f.{ a.x + b.x, a.y + b.y };
+#operator- macro (a, b: V2f) => V2f.{ a.x - b.x, a.y - b.y };
+#operator* macro (a: V2f, s: f32) => V2f.{ a.x * s, a.y * s };
-#operator+= (a: ^V2f, b: V2f) {
+#operator+= macro (a: ^V2f, b: V2f) {
a.x += b.x;
a.y += b.y;
}
-#operator-= (a: ^V2f, b: V2f) {
+#operator-= macro (a: ^V2f, b: V2f) {
a.x -= b.x;
a.y -= b.y;
}
-#operator*= (a: ^V2f, s: f32) {
+#operator*= macro (a: ^V2f, s: f32) {
a.x += s;
a.y += s;
}