T* base_ptr;
T* end_ptr;
T* curr_ptr;
-
+
void init(i32 max_members = 16)
{
base_ptr = (T *) malloc(sizeof(T) * max_members);
curr_ptr = base_ptr;
end_ptr = base_ptr + max_members;
}
-
+
void free_all()
{
free(base_ptr);
}
-
+
void reset()
{
curr_ptr = base_ptr;
}
-
+
T* alloc()
{
if (curr_ptr >= end_ptr) return nullptr;
-
+
auto res = curr_ptr;
curr_ptr += 1;
return res;
{
float x, y;
float w, h;
-
+
bool contains(float ox, float oy) const;
bool intersects(AABB other) const;
};
-#define QUAD_TREE_POINTS_PER_NODE 8
+#define QUAD_TREE_POINTS_PER_NODE 4
template <typename T>
struct QuadTree
{
T* points[QUAD_TREE_POINTS_PER_NODE];
u32 point_count;
AABB region;
-
+
QuadTree<T>* nw;
QuadTree<T>* ne;
QuadTree<T>* sw;
QuadTree<T>* se;
-
+
void init(AABB initial_region)
{
region = initial_region;
sw = nullptr;
se = nullptr;
point_count = 0;
-
+
foreach (i, 0, QUAD_TREE_POINTS_PER_NODE)
{
points[i] = nullptr;
}
}
-
+
void subdivide(FixedArenaAllocator<QuadTree<T>>* a)
{
if (nw != nullptr) return;
-
+
auto hw = region.w / 2.0f;
auto hh = region.h / 2.0f;
-
+
nw = a->alloc();
ne = a->alloc();
sw = a->alloc();
se = a->alloc();
-
+
nw->init(AABB { region.x, region.y, hw, hh });
ne->init(AABB { region.x + hw, region.y, hw, hh });
sw->init(AABB { region.x, region.y + hh, hw, hh });
se->init(AABB { region.x + hw, region.y + hh, hw, hh });
}
-
+
bool insert(T* t, FixedArenaAllocator<QuadTree<T>>* a)
{
V2f pos = t->pos; // T is expected to have a 'pos' member.
-
+
if (!region.contains(pos.x, pos.y)) return false;
-
+
if (point_count < QUAD_TREE_POINTS_PER_NODE && nw == nullptr)
{
points[point_count] = t;
point_count += 1;
return true;
}
-
+
if (nw == nullptr) this->subdivide(a);
-
+
if (nw->insert(t, a)) return true;
if (ne->insert(t, a)) return true;
if (sw->insert(t, a)) return true;
if (se->insert(t, a)) return true;
-
+
return false;
}
-
+
void query(AABB r, Array<T*>* point_list) const
{
if (!region.intersects(r)) return;
-
+
foreach (i, 0, point_count)
if (r.contains(points[i]->pos.x, points[i]->pos.y)) point_list->push(points[i]);
-
+
if (nw == nullptr) return;
-
+
nw->query(r, point_list);
ne->query(r, point_list);
sw->query(r, point_list);
{
V2f offset;
f32 scale;
+ i32 window_width, window_height;
};
-void camera_to_mat4(Camera cam, mat4* mat);
+void camera_ortho_mat4(Camera cam, mat4* mat);
+void camera_world_mat4(Camera cam, mat4* mat);
u32 load_shader(u32 shader_type, const char* shader_loc);
#endif // defer
-#endif //UTILS_H
\ No newline at end of file
+#endif //UTILS_H
out float planet_color_idx;
uniform mat4 u_proj;
+uniform mat4 u_camera;
void main() {
- gl_Position = u_proj * vec4(a_shape_pos * a_mass + a_obj_pos, 0, 1);
+ gl_Position = u_proj * u_camera * vec4(a_shape_pos * a_mass + a_obj_pos, 0, 1);
planet_color_idx = a_planet_color_idx;
-}
\ No newline at end of file
+}
#include "ui.h"
#include "log.h"
+// TODO(Brendan): Move this
#define PI 3.141592653589793238462643383
#define WINDOW_WIDTH 1600
#define WINDOW_TITLE "N-Body Simulation"
// :ArbitraryConstant
-#define PARTICLE_COUNT 1500
+#define PARTICLE_COUNT 2500
+// TODO(Brendan): Maybe this can be removed because it isn't really necessary?
internal void
glfw_key_handler(GLFWwindow* window, i32 key, i32 scancode, i32 action, i32 mods)
{
glfwSetWindowShouldClose(window, 1);
}
-internal i32 window_width;
-internal i32 window_height;
-
-internal void
-glfw_resize_handler(GLFWwindow* window, i32 width, i32 height)
-{
- window_width = width;
- window_height = height;
-}
-
internal void
glfw_error_handler(i32 error, const char* desc)
{
glfwSwapInterval(1);
glfwSetKeyCallback(window, glfw_key_handler);
- glfwSetFramebufferSizeCallback(window, glfw_resize_handler);
// NOTE(Brendan): This may need to be changed if the screen orientation changes.
glEnable(GL_CULL_FACE);
Array<Body> bodies;
QuadTree<Body> qt_bodies;
FixedArenaAllocator<QuadTree<Body>> qt_body_allocator;
+
+ Camera camera;
};
internal void
}
state->qt_body_allocator.init(PARTICLE_COUNT);
+
+ state->camera.offset = V2f { 0, 0 };
+ state->camera.scale = 1.0f;
}
// NOTE(Brendan): dt is expected to be in units of "per second".
internal void
update(SimState* state, f64 dt)
{
+ glfwGetWindowSize(window, &state->camera.window_width, &state->camera.window_height);
+
+ persist const f32 camera_move_speed = 6;
+ if (glfwGetKey(window, GLFW_KEY_UP)) state->camera.offset.y -= camera_move_speed;
+ if (glfwGetKey(window, GLFW_KEY_DOWN)) state->camera.offset.y += camera_move_speed;
+ if (glfwGetKey(window, GLFW_KEY_LEFT)) state->camera.offset.x -= camera_move_speed;
+ if (glfwGetKey(window, GLFW_KEY_RIGHT)) state->camera.offset.x += camera_move_speed;
+ if (glfwGetKey(window, GLFW_KEY_Q)) state->camera.scale *= 1.01f;
+ if (glfwGetKey(window, GLFW_KEY_A)) state->camera.scale /= 1.01f;
+
persist const f64 step = 0.01;
- state->qt_bodies.init(AABB { -(f32) window_width, -(f32)window_height, (f32) window_width * 2, (f32) window_height * 2 });
+ state->qt_bodies.init(AABB { -2000, -2000, 4000, 4000 });
state->qt_body_allocator.reset();
For (state->bodies) state->qt_bodies.insert(&it, &state->qt_body_allocator);
glUseProgram(body_program);
mat4 ortho_mat;
- mat4_ortho(&ortho_mat, 0, window_width, 0, window_height, 0.0f, 100.0f);
+ camera_ortho_mat4(state->camera, &ortho_mat);
GLuint ortho_mat_loc = glGetUniformLocation(body_program, "u_proj");
glUniformMatrix4fv(ortho_mat_loc, 1, false, (f32 *) ortho_mat);
- glViewport(0, 0, window_width, window_height);
+ glViewport(0, 0, state->camera.window_width, state->camera.window_height);
+
+ mat4 camera_mat;
+ camera_world_mat4(state->camera, &camera_mat);
+ GLuint camera_mat_loc = glGetUniformLocation(body_program, "u_camera");
+ glUniformMatrix4fv(camera_mat_loc, 1, false, (f32 *) camera_mat);
// NOTE(Brendan): Clear the screen.
glClearColor(0.1, 0.1, 0.1, 1.0);
frame_delta += delta;
if (frame_delta >= 1.0)
{
- // logprint(LOG_LEVEL_INFO, "AVG UPD CLK: %10.6f", (f64) (total_clock_delta / frame_count) / CLOCKS_PER_SEC);
-
total_clock_delta = 0;
frame_delta -= 1.0;
frame_rate = frame_count;
panic_and_die(const char* msg, ...)
{
puts("************ PANIC ************");
-
+
va_list va;
va_start(va, msg);
logvprint(LOG_LEVEL_ERROR, msg, va);
va_end(va);
-
+
#ifdef DEBUG
// NOTE: This allows for a debugger to stop here.
__asm("int $3");
#endif
-
+
exit(1);
}
void
-camera_to_mat4(Camera cam, mat4* mat)
+camera_ortho_mat4(Camera cam, mat4* mat)
+{
+ mat4_ortho(mat, 0, cam.window_width, 0, cam.window_height, 0.0f, 100.0f);
+}
+
+void
+camera_world_mat4(Camera cam, mat4* mat)
{
(*mat)[0] = cam.scale;
(*mat)[1] = 0.0f;
(*mat)[9] = 0.0f;
(*mat)[10] = 0.0f;
(*mat)[11] = 0.0f;
- (*mat)[12] = cam.scale * cam.offset.x;
- (*mat)[13] = cam.scale * cam.offset.y;
+ (*mat)[12] = cam.scale * -cam.offset.x + (1 - cam.scale) * (cam.window_width / 2);
+ (*mat)[13] = cam.scale * -cam.offset.y + (1 - cam.scale) * (cam.window_height / 2);
(*mat)[14] = 0.0f;
(*mat)[15] = 1.0f;
}
load_shader(GLenum shader_type, const char* shader_loc)
{
logprint(LOG_LEVEL_INFO, "Loading shader: %s", shader_loc);
-
+
GLuint shader = glCreateShader(shader_type);
-
+
FILE* shader_file = fopen(shader_loc, "rb");
defer { fclose(shader_file); };
if (shader_file == NULL) panic_and_die("Shader file not found: %s\n", shader_loc);
-
+
fseek(shader_file, 0, SEEK_END);
i32 shader_file_size = ftell(shader_file);
fseek(shader_file, 0, SEEK_SET);
-
+
char* shader_buffer = (char *) malloc(shader_file_size + 1);
defer { free(shader_buffer); };
fread(shader_buffer, 1, shader_file_size, shader_file);
-
+
shader_buffer[shader_file_size] = 0;
-
+
glShaderSource(shader, 1, (const char* const*) &shader_buffer, NULL);
glCompileShader(shader);
-
+
GLint successful;
glGetShaderiv(shader, GL_COMPILE_STATUS, &successful);
if (successful != GL_TRUE)
GLchar shader_log[1024];
glGetShaderInfoLog(shader, 1023, &log_length, shader_log);
shader_log[log_length] = 0;
-
+
panic_and_die("Error compiling shader %s:\n%s\n",
shader_loc,
shader_log);
}
-
+
return shader;
}
create_program(GLuint vertex_shader, GLuint fragment_shader)
{
logprint(LOG_LEVEL_INFO, "Linking GL program");
-
+
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
-
+
GLint successful;
glGetProgramiv(program, GL_LINK_STATUS, &successful);
if (successful != GL_TRUE)
GLchar program_log[1024];
glGetProgramInfoLog(program, 1023, &log_length, program_log);
program_log[log_length] = 0;
-
+
panic_and_die("Error linking program:\n%s", program_log);
}
-
+
return program;
}