build/utils.o \
build/vecmath.o \
build/physics.o \
+ build/settings.o \
build/ui.o \
build/sim.o
--- /dev/null
+# Determines the number of parallel execution units to be used.
+# This must be at least 2 (for now).
+thread_count 4
+
+# Determines the number of physics bodies in the simulation.
+body_count 2500
+
+# Determines the number of different types of bodies.
+# This must be specified before the body_color or interaction settings.
+body_type_count 4
+
+# Determines what the color is of each of the body types.
+# Uses standard RGB with values ranging from 0 to 1.
+# Type# R G B
+body_color 0 1.0 0.0 0.0
+body_color 1 0.0 1.0 0.0
+body_color 2 0.0 0.0 1.0
+body_color 3 1.0 1.0 1.0
+
+# Determines the range of values a bodies mass can be, sampled from
+# a uniform distribution.
+# Type# Min Max
+body_mass_range 0 2.0 4.0
+body_mass_range 1 20.0 22.0
+body_mass_range 2 5.0 7.0
+body_mass_range 3 3.0 15.0
+
+# Determines the friction coeffient, u.
+# Equation of friction used:
+# F = -u * v;
+# where v is the velocity of the body.
+# Set to 0.0 to watch very wild behavior.
+friction 6.0
+
+# Determines the scale of the interaction calcuations.
+# Mostly an implementation detail, but effectively, the "distance" column on
+# the interactions plus one, is multipled by this number and that is the maximum distance
+# two bodies will interact in terms of pixels.
+universe_scale 20.0
+
+# Determines how two bodies will interact. Note, that this is not a symmetric relation.
+# Body Type# Other Type# Distance Force
+interaction 0 1 5.0 200.0
data = nullptr;
}
+ void init(u32 initial_capacity)
+ {
+ count = 0;
+ capacity = 0;
+ data = nullptr;
+ this->ensure_capacity(initial_capacity);
+ }
+
T& operator[](i32 elem)
{
#if defined(DEBUG)
#ifndef LOG_H
#define LOG_H
+#include <stdarg.h>
+
enum LogLevel
{
LOG_LEVEL_INFO,
void logprint(LogLevel level, const char* format, ...);
void logvprint(LogLevel level, const char* format, va_list va);
-#endif //LOG_H
\ No newline at end of file
+#endif //LOG_H
#include "container.h"
#include "utils.h"
-enum struct BodyType : u8
-{
- Red = 0,
- Green = 1,
- Blue = 2,
- White = 3,
-
- Count
-};
-
struct Body
{
V2f pos;
V2f vel;
V2f acc;
-
+
f32 mass;
-
- BodyType body_type;
+
+ u32 body_type;
+};
+
+// NOTE(Brendan): This represents the piecewise function:
+//
+// F(d) = {
+// 0 < d < 1: r * (1 - d) / d
+// 1 <= d < distance_range + 1: (-4 * max_force / (distance_range ^ 2)) * (d - (distance_range / 2) - 1) ^ 2 + max_force,
+// otherwise: 0
+// }
+struct BodyRelation
+{
+ f32 distance_range;
+ f32 max_force;
};
void nocheckin_init_other_bodies();
void body_accumulate_move(Body* body, QuadTree<Body>* qt_bodies, f64 dt);
void body_apply_move(Body* body, f64 dt);
-#endif //PHYSICS_H
\ No newline at end of file
+#endif //PHYSICS_H
--- /dev/null
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include "container.h"
+#include "log.h"
+#include "utils.h"
+#include "physics.h"
+
+struct BodyColor
+{
+ f32 r, g, b;
+};
+
+struct BodyMassRange
+{
+ f32 min, max;
+};
+
+struct SimSettings
+{
+ u32 body_count;
+ u32 body_type_count;
+
+ Array<BodyColor> body_colors;
+ Array<BodyMassRange> body_mass_range;
+
+ // NOTE(Brendan): This is effectively a 2D array.
+ // Accessed using [b1 * num_bodies + b2]
+ Array<BodyRelation> body_relations;
+
+ f32 friction;
+ f32 near_repulsive_force;
+ f32 universe_scale;
+ u32 thread_count;
+};
+
+extern SimSettings global_settings;
+
+void load_settings_from_file(SimSettings* settings, const char* filename);
+void save_settings_to_file(SimSettings* settings, const char* filename);
+void generate_random_settings(SimSettings* settings);
+
+#endif
#include "physics.h"
#include "utils.h"
#include "types.h"
-
-// NOTE(Brendan): This represents the piecewise function:
-//
-// F(d) = {
-// 0 < d < 1: r * (1 - d) / d
-// 1 <= d < distance_range + 1: (-4 * max_force / (distance_range ^ 2)) * (d - (distance_range / 2) - 1) ^ 2 + max_force,
-// otherwise: 0
-// }
-struct BodyRelation
-{
- f32 distance_range;
- f32 max_force;
-};
+#include "settings.h"
internal f32
get_force_magnitude_at_distance(BodyRelation br, f32 d)
{
if (0 < d && d < 1)
{
- persist const f32 repulsion_force = 100.0f; // :ArbitraryConstant
- return repulsion_force * (1 - d) / d;
+ return global_settings.near_repulsive_force * (1 - d) / d;
}
if (1 <= d && d < br.distance_range + 1)
return 0;
}
-internal BodyRelation body_relations[(i32) BodyType::Count][(i32) BodyType::Count];
-
internal bool
bodies_collide(Body* b1, Body* b2)
{
thread_local internal Array<Body *> other_bodies;
void nocheckin_init_other_bodies()
{
- foreach (i, 0, (i32) BodyType::Count)
- {
- foreach (j, 0, (i32) BodyType::Count)
- {
- body_relations[i][j].max_force = randf(-200.0f, 200.0f);
- body_relations[i][j].distance_range = randf(4.0f, 7.0f);
- }
- }
-
other_bodies.ensure_capacity(1024);
}
if (body == it) continue;
auto norm_dir = body->pos - it->pos;
- auto d = v2f_mag(norm_dir) / 20.0f; // :ArbitraryConstant
+ auto d = v2f_mag(norm_dir) / global_settings.universe_scale;
norm_dir = v2f_norm(norm_dir);
- auto br = body_relations[static_cast<i32>(body->body_type)][static_cast<i32>(it->body_type)];
+ auto br = global_settings.body_relations[static_cast<i32>(body->body_type) * global_settings.body_type_count + static_cast<i32>(it->body_type)];
f32 force_mag = get_force_magnitude_at_distance(br, d);
force += norm_dir * force_mag;
}
- force += body->vel * -6.f; // :ArbitraryConstant
+ force += body->vel * -global_settings.friction;
body->acc = force * (1.0f / body->mass);
body->vel += body->acc * dt;
--- /dev/null
+#include "settings.h"
+
+SimSettings global_settings;
+
+void
+load_settings_from_file(SimSettings* settings, const char* filename)
+{
+ FILE* file = fopen(filename, "r");
+ defer { fclose(file); };
+
+
+}
+
+void
+save_settings_to_file(SimSettings* settings, const char* filename)
+{
+}
+
+void
+generate_random_settings(SimSettings* settings)
+{
+ settings->body_count = 2500;
+
+ const u32 num_body_types = 4;
+ settings->body_type_count = num_body_types;
+
+ settings->body_colors.init(num_body_types);
+ settings->body_colors[0] = { 1.0, 0.0, 0.0 };
+ settings->body_colors[1] = { 0.0, 1.0, 0.0 };
+ settings->body_colors[2] = { 0.0, 0.0, 1.0 };
+ settings->body_colors[3] = { 1.0, 1.0, 1.0 };
+
+ settings->body_mass_range.init(num_body_types);
+ settings->body_mass_range[0] = { 4.0, 6.0 };
+ settings->body_mass_range[1] = { 4.0, 6.0 };
+ settings->body_mass_range[2] = { 4.0, 6.0 };
+ settings->body_mass_range[3] = { 4.0, 6.0 };
+
+ settings->friction = 6.0;
+ settings->near_repulsive_force = 100.0;
+ settings->universe_scale = 20.0;
+
+ settings->thread_count = 4;
+
+ settings->body_relations.init(num_body_types * num_body_types);
+ foreach (i, 0, num_body_types)
+ {
+ foreach (j, 0, num_body_types)
+ {
+ settings->body_relations[i * num_body_types] =
+ {
+ .distance_range = randf(4.0f, 7.0f),
+ .max_force = randf(-200.0f, 200.0f),
+ };
+ }
+ }
+}
#include "physics.h"
#include "ui.h"
#include "log.h"
-
-// :ArbitraryConstant
-#define PARTICLE_COUNT 2500
-
-// :ArbitraryConstant
-#define NUM_THREADS 2
+#include "settings.h"
// TODO(Brendan): Maybe this can be removed because it isn't really necessary?
internal void
Camera camera;
pthread_barrier_t thread_sync_barrier;
- pthread_t threads[NUM_THREADS - 1];
- ThreadData thread_data[NUM_THREADS - 1];
+ Array<pthread_t> threads;
+ Array<ThreadData> thread_data;
};
+// @CLEANUP
internal f64 TEMP_dt = 0;
internal void
update_bodies_partial(SimState *state, i32 index)
{
- i32 low = index * (PARTICLE_COUNT / NUM_THREADS);
- i32 high = (index + 1) * (PARTICLE_COUNT / NUM_THREADS);
-
- persist const f64 step = 0.01;
+ i32 low = index * (global_settings.body_count / global_settings.thread_count);
+ i32 high = (index + 1) * (global_settings.body_count / global_settings.thread_count);
foreach (i, low, high) body_accumulate_move(&state->bodies[i], &state->qt_bodies, TEMP_dt);
pthread_barrier_wait(&state->thread_sync_barrier);
sim_state_init(SimState* state)
{
// NOTE(Brendan): Need to initialize the array since it does not get constructed because I refuse to use the 'new' keyword. alloc<T> uses malloc under the hood and cannot initialize the result.
- state->bodies.init();
- state->bodies.ensure_capacity(PARTICLE_COUNT);
+ state->bodies.init(global_settings.body_count);
- foreach (i, 0, PARTICLE_COUNT)
+ foreach (i, 0, global_settings.body_count)
{
Body tmp_body;
+ tmp_body.body_type = (rand() % global_settings.body_type_count);
tmp_body.pos = V2f{ randf(-1000, 1000), randf(-1000, 1000) };
tmp_body.vel = V2f{ 0.0f, 0.0f };
- tmp_body.mass = randf(3.0f, 6.0f);
- tmp_body.body_type = static_cast<BodyType> ((rand() % 4));
+
+ BodyMassRange bmr = global_settings.body_mass_range[tmp_body.body_type];
+ tmp_body.mass = randf(bmr.min, bmr.max);
+
state->bodies.push(tmp_body);
}
- state->qt_body_allocator.init(PARTICLE_COUNT);
+ state->qt_body_allocator.init(global_settings.body_count);
state->qt_bodies.init(AABB { -2000, -2000, 4000, 4000 });
state->camera.scale = 1.0f;
- pthread_barrier_init(&state->thread_sync_barrier, NULL, NUM_THREADS);
+ pthread_barrier_init(&state->thread_sync_barrier, NULL, global_settings.thread_count);
+
+ state->threads.init(global_settings.thread_count);
+ state->threads.count = global_settings.thread_count;
- foreach (i, 0, NUM_THREADS - 1)
+ state->thread_data.init(global_settings.thread_count);
+ foreach (i, 0, global_settings.thread_count - 1)
{
- state->thread_data[i] = ThreadData { i, state };
+ state->thread_data.push(ThreadData { i, state });
pthread_create(&state->threads[i], NULL, thread_start, (void *) &state->thread_data[i]);
}
}
{
srand(time(NULL));
+ generate_random_settings(&global_settings);
+
init_glfw();
defer { deinit_glfw(); };