added moving camera
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Oct 2020 02:12:51 +0000 (21:12 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Oct 2020 02:12:51 +0000 (21:12 -0500)
include/utils.h
res/shaders/planet_vert.glsl
src/sim.cpp
src/utils.cpp

index 09b321785e73e784319cc414dc7f5fc40ec0a8d3..604edbf4541e3248d561c2050e733af7b1e11128 100644 (file)
@@ -42,28 +42,28 @@ struct FixedArenaAllocator
     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;
@@ -75,24 +75,24 @@ struct AABB
 {
     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;
@@ -101,63 +101,63 @@ struct QuadTree
         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);
@@ -170,9 +170,11 @@ struct Camera
 {
     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);
@@ -223,4 +225,4 @@ operator*(defer_dummy, F f)
 
 #endif // defer
 
-#endif //UTILS_H
\ No newline at end of file
+#endif //UTILS_H
index ee7ccde13399eb0a065eb7ac72f09449fd83290e..2579da691bbe2ab22f32cb0e585f10b5f6075775 100644 (file)
@@ -10,9 +10,10 @@ layout(location = 3) in float a_planet_color_idx;
 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
+}
index d8f28d38b1ec23b4acbfe36bc4f3f0c73a1c1462..5103e7252221e1914a85804351a8d16347fa3755 100644 (file)
@@ -18,6 +18,7 @@
 #include "ui.h"
 #include "log.h"
 
+// TODO(Brendan): Move this
 #define PI 3.141592653589793238462643383
 
 #define WINDOW_WIDTH           1600
@@ -25,8 +26,9 @@
 #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)
 {
@@ -34,16 +36,6 @@ 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)
 {
@@ -66,7 +58,6 @@ init_glfw()
 
        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);
@@ -132,6 +123,8 @@ struct SimState
     Array<Body> bodies;
     QuadTree<Body> qt_bodies;
     FixedArenaAllocator<QuadTree<Body>> qt_body_allocator;
+
+    Camera camera;
 };
 
 internal void
@@ -152,15 +145,28 @@ sim_state_init(SimState* state)
     }
 
     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);
 
@@ -187,10 +193,15 @@ draw(SimState* state)
     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);
@@ -240,8 +251,6 @@ loop(SimState* state)
         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;
index c080ccad5ff436f6dc8280a78b2d210a9cab93a5..c408c700411d2a5599ba68f44f09d49837d9bf39 100644 (file)
@@ -11,17 +11,17 @@ void
 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);
 }
 
@@ -51,7 +51,13 @@ bool AABB::intersects(AABB other) const
 
 
 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;
@@ -65,8 +71,8 @@ camera_to_mat4(Camera cam, mat4* mat)
     (*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;
 }
@@ -76,26 +82,26 @@ GLuint
 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)
@@ -104,12 +110,12 @@ load_shader(GLenum shader_type, const char* shader_loc)
         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;
 }
 
@@ -117,12 +123,12 @@ GLuint
 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)
@@ -131,9 +137,9 @@ create_program(GLuint vertex_shader, GLuint fragment_shader)
         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;
 }