pink circle!
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 16 Oct 2020 16:46:55 +0000 (11:46 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 16 Oct 2020 16:46:55 +0000 (11:46 -0500)
12 files changed:
Makefile
include/physics.h [new file with mode: 0644]
include/types.h [new file with mode: 0644]
include/utils.h [new file with mode: 0644]
include/vecmath.h [new file with mode: 0644]
project.4coder
res/shaders/planet_frag.glsl [new file with mode: 0644]
res/shaders/planet_vert.glsl [new file with mode: 0644]
src/physics.c [new file with mode: 0644]
src/sim.c
src/utils.c [new file with mode: 0644]
src/vecmath.c [new file with mode: 0644]

index 56b386b56072ea1c4994040d12a5baf58ca11f41..a0c02c15c7ce25f3dde0840193a5c79490e5b212 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
 RELEASE=0
 
 OBJ_FILES=\
+       build/utils.o \
+       build/vecmath.o \
+       build/physics.o \
        build/sim.o
 
 ifeq (, $(shell which tcc))
diff --git a/include/physics.h b/include/physics.h
new file mode 100644 (file)
index 0000000..f79b9ba
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef PHYSICS_H
+#define PHYSICS_H
+
+#include <vecmath.h>
+
+typedef struct Body {
+    V2f pos;
+    V2f vel;
+    
+    f32 mass;
+} Body;
+
+#endif //PHYSICS_H
diff --git a/include/types.h b/include/types.h
new file mode 100644 (file)
index 0000000..a471fbd
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <stdint.h>
+
+// NOTE(brendan): Standard remaps for common types.
+//                This ensures that the exact size of the type is known.
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef float f32;
+typedef double f64;
+
+#endif //TYPES_H
diff --git a/include/utils.h b/include/utils.h
new file mode 100644 (file)
index 0000000..1c0e0dc
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <stdint.h> // NOTE(Brendan): Only for intptr_t
+
+// NOTE(Brendan): Hacky way to get the offset of a struct member.
+// offsetof() is the standard way in C to get it, but it is not guarenteed
+// to be defined in all C implementations.
+#define offset_of(S, mem) (intptr_t) &(((S*)(0))->mem)
+
+// NOTE(Brendan): This is useful in many situations and I believe it cleans up the code by making simple, counter based for loops easier to recognize at a glance.
+#define foreach(var, lo, hi) for (i32 var = lo; var < hi; var++)
+
+void _Noreturn panic_and_die(const char* msg, ...);
+
+#endif //UTILS_H
\ No newline at end of file
diff --git a/include/vecmath.h b/include/vecmath.h
new file mode 100644 (file)
index 0000000..8853176
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef VECMATH_H
+#define VECMATH_H
+
+#include "types.h"
+
+typedef struct V2f { f32 x, y; } V2f;
+
+V2f v2f_add (V2f a, V2f b);
+V2f v2f_sub (V2f a, V2f b);
+V2f v2f_mul (V2f a, f32 scalar);
+f32 v2f_dot (V2f a, V2f b);
+f32 v2f_smag(V2f a);
+f32 v2f_mag (V2f a);
+V2f v2f_norm(V2f a);
+V2f v2f_proj(V2f a, V2f onto);
+
+
+#endif //VECMATH_H
index f69491318831dd1bacacab43f2c4744c2f42e70c..fa79a8e8213126fe0f84d97c5a6da544ec572ae9 100644 (file)
@@ -5,7 +5,10 @@ project_name = "CSC718_Project";
 patterns = {
 "*.c",
 "*.h",
+"*.sh",
+"*.glsl",
 "*.4coder",
+"Makefile",
 };
 
 blacklist_patterns = {
diff --git a/res/shaders/planet_frag.glsl b/res/shaders/planet_frag.glsl
new file mode 100644 (file)
index 0000000..863ee86
--- /dev/null
@@ -0,0 +1,9 @@
+#version 300 es
+
+precision mediump float;
+
+out vec4 fragColor;
+
+void main() {
+       fragColor = vec4(1.0, 0.0, 1.0, 1.0);
+}
diff --git a/res/shaders/planet_vert.glsl b/res/shaders/planet_vert.glsl
new file mode 100644 (file)
index 0000000..594d966
--- /dev/null
@@ -0,0 +1,11 @@
+#version 300 es
+
+precision mediump float;
+
+layout(location = 0) in vec2 a_shape_pos;
+layout(location = 1) in vec2 a_obj_pos;
+layout(location = 2) in float a_mass;
+
+void main() {
+       gl_Position = vec4(a_shape_pos, 0, 1);
+}
\ No newline at end of file
diff --git a/src/physics.c b/src/physics.c
new file mode 100644 (file)
index 0000000..5f4f488
--- /dev/null
@@ -0,0 +1,2 @@
+#include "physics.h"
+
index f81b8c1738012b5b9315e1b5c54e29efc55a85bd..3f452b6cfeeb78f5c594bb24fed183152fa2c0ce 100644 (file)
--- a/src/sim.c
+++ b/src/sim.c
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <malloc.h>
-#include <stdarg.h>
+#include <alloca.h>
 #include <unistd.h>
+#include <math.h>
 
 #include <GLES3/gl3.h>
 #include <GLFW/glfw3.h>
 
+#include "types.h"
+#include "utils.h"
+#include "physics.h"
+
+#define PI 3.141592653589793238462643383
+
 #define WINDOW_WIDTH           1600
 #define WINDOW_HEIGHT          900
 #define WINDOW_TITLE           "N-Body Simulation"
 
-void panic_and_die(const char* msg, ...) __attribute__((noreturn));
-void panic_and_die(const char* msg, ...) {
-       puts("************ PANIC ************");
-    
-       va_list va;
-       va_start(va, msg);
-       vprintf(msg, va);
-       va_end(va);
-    
-#ifdef DEBUG
-       // NOTE: This allows for a debugger to stop here.
-       __asm("int $3");
-#endif
-    
-       exit(1);
-}
-
-void glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods) {
+void glfw_key_handler(GLFWwindow* window, i32 key, i32 scancode, i32 action, i32 mods) {
        if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
                glfwSetWindowShouldClose(window, 1);
 }
 
-void glfw_resize_handler(GLFWwindow* window, int width, int height) {
+void glfw_resize_handler(GLFWwindow* window, i32 width, i32 height) {
        glViewport(0, 0, width, height);
 }
 
-void glfw_error_handler(int error, const char* desc) {
+void glfw_error_handler(i32 error, const char* desc) {
        panic_and_die("GLFW Error (%d): %s\n", error, desc);
 }
 
 GLFWwindow* window;
-void init_opengl() {
+void init_glfw() {
        if (!glfwInit()) panic_and_die("Failed to initalize GLFW.");
        glfwSetErrorCallback(glfw_error_handler);
     
        window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
-       glfwMakeContextCurrent(window);
+    glfwMakeContextCurrent(window);
     
        glfwSwapInterval(1);
        glfwSetKeyCallback(window, glfw_key_handler);
        glfwSetFramebufferSizeCallback(window, glfw_resize_handler);
+    
+    glEnable(GL_CULL_FACE);
+    glCullFace(GL_CCW);
+}
+
+GLuint load_shader(GLenum shader_type, const char* shader_loc) {
+    GLuint shader = glCreateShader(shader_type);
+    
+    FILE* shader_file = fopen(shader_loc, "rb");
+    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 = malloc(shader_file_size + 1);
+    fread(shader_buffer, 1, shader_file_size, shader_file);
+    fclose(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) {
+        GLsizei log_length = 0;
+        GLchar shader_log[1024];
+        glGetShaderInfoLog(shader, 1023, &log_length, shader_log);
+        shader_log[log_length] = 0;
+        
+        panic_and_die("Error compiling %s:\n%s\n", shader_loc, shader_log);
+    }
+    
+    free(shader_buffer);
+    
+    return shader;
+}
+
+GLuint create_program(GLuint vertex_shader, GLuint fragment_shader) {
+    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) {
+        GLsizei log_length = 0;
+        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;
+}
+
+
+
+
+
+
+
+#define CIRCLE_POINT_COUNT 36 // NOTE(Brendan): Treat a circle as a many-sided polygon.
+
+// NOTE(Brendan): Returns the VAO where the mesh data was bound.
+GLsizei create_circle_mesh() {
+    GLsizei vao;
+    glGenVertexArrays(1, &vao);
+    glBindVertexArray(vao);
+    
+    V2f circle_points[CIRCLE_POINT_COUNT] = {};
+    foreach (i, 0, CIRCLE_POINT_COUNT) {
+        f32 t = (f32) i / (f32) CIRCLE_POINT_COUNT;
+        circle_points[i].x = cos(t * 2 * PI) / 2.0f;
+        circle_points[i].y = sin(t * 2 * PI) / 2.0f;
+    }
+    
+    GLsizei vertex_buffer;
+    glGenBuffers(1, &vertex_buffer);
+    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(circle_points), &circle_points, GL_STATIC_DRAW);
+    glEnableVertexAttribArray(0);
+    glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(V2f), (void *) offset_of(V2f, x));
+    glBindBuffer(GL_ARRAY_BUFFER, -1);
+    
+    u8 circle_indicies[CIRCLE_POINT_COUNT] = {};
+    foreach(i, 0, CIRCLE_POINT_COUNT) circle_indicies[i] = i;
+    
+    GLsizei index_buffer;
+    glGenBuffers(1, &index_buffer);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(circle_indicies), &circle_indicies, GL_STATIC_DRAW);
+    
+    glBindVertexArray(-1);
+    
+    return vao;
 }
 
 void deinit_opengl() {
@@ -63,39 +154,52 @@ void deinit_opengl() {
        glfwTerminate();
 }
 
-// NOTE: dt is expected to be in units of "per second".
-void update(double dt) {
+// NOTE(Brendan): dt is expected to be in units of "per second".
+void update(f64 dt) {
 }
 
+GLsizei circle_mesh;
 void draw() {
        glClearColor(0.1, 0.1, 0.1, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-       glfwSwapBuffers(window);
+    
+    glBindVertexArray(circle_mesh);
+    glDrawElements(GL_TRIANGLE_FAN, CIRCLE_POINT_COUNT, GL_UNSIGNED_BYTE, 0);
+    glBindVertexArray(-1);
+    
+    glfwSwapBuffers(window);
 }
 
 void loop() {
-       double last_time = glfwGetTime();
-       double curr_time = last_time;
-       double delta;
+    f64 last_time = glfwGetTime();
+    f64 curr_time = last_time;
+    f64 delta;
     
-       while (!glfwWindowShouldClose(window)) {
-               glfwPollEvents();
+    while (!glfwWindowShouldClose(window)) {
+        glfwPollEvents();
         
-               curr_time = glfwGetTime();
-               delta = curr_time - last_time;
-               last_time = curr_time;
+        curr_time = glfwGetTime();
+        delta = curr_time - last_time;
+        last_time = curr_time;
         
         if (delta > 0.0) {
-            
             update(delta);
             draw();
         }
-       }
+    }
 }
 
-int main(int argc, char* argv[]) {
-       init_opengl();
+i32 main(i32 argc, char* argv[]) {
+       init_glfw();
+    circle_mesh = create_circle_mesh();
+    
+    GLuint v_shader = load_shader(GL_VERTEX_SHADER, "res/shaders/planet_vert.glsl");
+    GLuint f_shader = load_shader(GL_FRAGMENT_SHADER, "res/shaders/planet_frag.glsl");
+    GLuint program = create_program(v_shader, f_shader);
+    
+    glUseProgram(program);
        loop();
+    
        deinit_opengl();
     
        return 0;
diff --git a/src/utils.c b/src/utils.c
new file mode 100644 (file)
index 0000000..96faa94
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+void panic_and_die(const char* msg, ...) {
+       puts("************ PANIC ************");
+    
+       va_list va;
+       va_start(va, msg);
+       vprintf(msg, va);
+       va_end(va);
+    
+#ifdef DEBUG
+       // NOTE: This allows for a debugger to stop here.
+       __asm("int $3");
+#endif
+    
+       exit(1);
+}
\ No newline at end of file
diff --git a/src/vecmath.c b/src/vecmath.c
new file mode 100644 (file)
index 0000000..8f9382c
--- /dev/null
@@ -0,0 +1,36 @@
+#include "vecmath.h"
+#include <math.h>
+
+V2f v2f_add(V2f a, V2f b) {
+    return (V2f) { .x = a.x + b.x, .y = a.y + b.y };
+}
+
+V2f v2f_sub(V2f a, V2f b) {
+    return (V2f) { .x = a.x - b.x, .y = a.y - b.y };
+}
+
+V2f v2f_mul(V2f a, f32 scalar) {
+    return (V2f) { .x = a.x * scalar, .y = a.y * scalar };
+}
+
+f32 v2f_dot(V2f a, V2f b) {
+    return a.x * b.x + a.y * b.y;
+}
+
+f32 v2f_smag(V2f a) {
+    return v2f_dot(a, a);
+}
+
+f32 v2f_mag(V2f a) {
+    return sqrt(v2f_smag(a));
+}
+
+V2f v2f_norm(V2f a) {
+    const f32 mag = v2f_mag(a);
+    return v2f_mul(a, 1.0f / mag);
+}
+
+V2f v2f_proj(V2f a, V2f onto) {
+    const f32 dp = v2f_dot(a, onto) / v2f_mag(onto);
+    return v2f_mul(onto, dp);
+}
\ No newline at end of file