diff options
author | Bad Diode <bd@badd10de.dev> | 2021-01-26 09:25:04 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-01-26 10:34:46 +0100 |
commit | 21924d5e08814cc9028dc3866d8b97d8422807f4 (patch) | |
tree | 2e185715bdb0521be5c67633defa51fd64c03713 | |
parent | 71ab55ad22abd7ba8d6c41fa4c9ff5aa69db8284 (diff) | |
download | mic-opengl-example-21924d5e08814cc9028dc3866d8b97d8422807f4.tar.gz mic-opengl-example-21924d5e08814cc9028dc3866d8b97d8422807f4.zip |
Add triangle rendering w/ shader recompilation
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | shaders/triangle.frag | 5 | ||||
-rw-r--r-- | shaders/triangle.vert | 5 | ||||
-rw-r--r-- | src/app.c | 113 | ||||
-rw-r--r-- | src/app.h | 4 |
5 files changed, 123 insertions, 7 deletions
@@ -3,10 +3,13 @@ | |||
3 | 3 | ||
4 | # Source code location and files to watch for changes. | 4 | # Source code location and files to watch for changes. |
5 | SRC_DIR := src | 5 | SRC_DIR := src |
6 | SHADERS_DIR := shaders | ||
6 | SRC_MAIN := $(SRC_DIR)/main.c | 7 | SRC_MAIN := $(SRC_DIR)/main.c |
7 | SRC_APP := $(SRC_DIR)/app.c | 8 | SRC_APP := $(SRC_DIR)/app.c |
8 | WATCH_SRC := $(wildcard $(SRC_DIR)/*.c) | 9 | WATCH_SRC := $(wildcard $(SRC_DIR)/*.c) |
9 | WATCH_SRC += $(wildcard $(SRC_DIR)/*.h) | 10 | WATCH_SRC += $(wildcard $(SRC_DIR)/*.h) |
11 | WATCH_SRC += $(wildcard $(SHADERS_DIR)/*.vert) | ||
12 | WATCH_SRC += $(wildcard $(SHADERS_DIR)/*.frag) | ||
10 | 13 | ||
11 | # Output library names and executables. | 14 | # Output library names and executables. |
12 | BIN_NAME := app | 15 | BIN_NAME := app |
diff --git a/shaders/triangle.frag b/shaders/triangle.frag new file mode 100644 index 0000000..e8bde66 --- /dev/null +++ b/shaders/triangle.frag | |||
@@ -0,0 +1,5 @@ | |||
1 | #version 330 core | ||
2 | out vec4 frag_col; | ||
3 | void main() { | ||
4 | frag_col = vec4(0.8f, 0.8f, 0.8f, 1.0f); | ||
5 | } | ||
diff --git a/shaders/triangle.vert b/shaders/triangle.vert new file mode 100644 index 0000000..d5168a8 --- /dev/null +++ b/shaders/triangle.vert | |||
@@ -0,0 +1,5 @@ | |||
1 | #version 330 core | ||
2 | layout (location = 0) in vec3 vertex; | ||
3 | void main() { | ||
4 | gl_Position = vec4(vertex.x, vertex.y, vertex.z, 1.0); | ||
5 | } | ||
@@ -1,6 +1,62 @@ | |||
1 | #include "app.h" | 1 | #include "app.h" |
2 | #include "platform.h" | 2 | #include "platform.h" |
3 | 3 | ||
4 | bool | ||
5 | compile_shaders(const char *vert, const char *frag, u32 *handle, | ||
6 | PlatformAPI platform) { | ||
7 | int success = 0; | ||
8 | char memory[MB(1)] = {0}; // Memory for reading shader files | ||
9 | |||
10 | // Initialize shader handles. | ||
11 | u32 vert_handle = glCreateShader(GL_VERTEX_SHADER); | ||
12 | u32 frag_handle = glCreateShader(GL_FRAGMENT_SHADER); | ||
13 | |||
14 | // Vertex shader. | ||
15 | { | ||
16 | platform.read_file(vert, memory); | ||
17 | const char * source = memory; | ||
18 | glShaderSource(vert_handle, 1, &source, NULL); | ||
19 | glCompileShader(vert_handle); | ||
20 | glGetShaderiv(vert_handle, GL_COMPILE_STATUS, &success); | ||
21 | if (!success) { | ||
22 | glDeleteShader(vert_handle); | ||
23 | glDeleteShader(frag_handle); | ||
24 | return false; | ||
25 | } | ||
26 | } | ||
27 | |||
28 | // Fragment shader. | ||
29 | { | ||
30 | platform.read_file(frag, memory); | ||
31 | const char * source = memory; | ||
32 | glShaderSource(frag_handle, 1, &source, NULL); | ||
33 | glCompileShader(frag_handle); | ||
34 | glGetShaderiv(frag_handle, GL_COMPILE_STATUS, &success); | ||
35 | if (!success) { | ||
36 | glDeleteShader(vert_handle); | ||
37 | glDeleteShader(frag_handle); | ||
38 | return false; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | // Program linkage. | ||
43 | *handle = glCreateProgram(); | ||
44 | glAttachShader(*handle, vert_handle); | ||
45 | glAttachShader(*handle, frag_handle); | ||
46 | glLinkProgram(*handle); | ||
47 | glGetProgramiv(*handle, GL_LINK_STATUS, &success); | ||
48 | if(!success) { | ||
49 | glDeleteProgram(*handle); | ||
50 | glDeleteShader(vert_handle); | ||
51 | glDeleteShader(frag_handle); | ||
52 | return false; | ||
53 | } | ||
54 | glDeleteShader(vert_handle); | ||
55 | glDeleteShader(frag_handle); | ||
56 | |||
57 | return true; | ||
58 | } | ||
59 | |||
4 | static inline bool | 60 | static inline bool |
5 | app_init(AppState *state, PlatformAPI platform) { | 61 | app_init(AppState *state, PlatformAPI platform) { |
6 | platform.log("INIT"); | 62 | platform.log("INIT"); |
@@ -14,7 +70,7 @@ app_init(AppState *state, PlatformAPI platform) { | |||
14 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | 70 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); |
15 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | 71 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); |
16 | 72 | ||
17 | // // Initialize window. | 73 | // Initialize window. |
18 | GLFWwindow* window = glfwCreateWindow(400, 300, "Hello MIC", NULL, NULL); | 74 | GLFWwindow* window = glfwCreateWindow(400, 300, "Hello MIC", NULL, NULL); |
19 | if (window == NULL) { | 75 | if (window == NULL) { |
20 | platform.log("ERROR: failed to create GLFW window"); | 76 | platform.log("ERROR: failed to create GLFW window"); |
@@ -33,8 +89,47 @@ app_init(AppState *state, PlatformAPI platform) { | |||
33 | // Initialize viewport. | 89 | // Initialize viewport. |
34 | glViewport(0, 0, 400, 300); | 90 | glViewport(0, 0, 400, 300); |
35 | 91 | ||
92 | // Initialize vertex data. | ||
93 | state->vertices[0] = -0.5f; | ||
94 | state->vertices[1] = -0.5f; | ||
95 | state->vertices[2] = 0.0f; | ||
96 | state->vertices[3] = 0.5f; | ||
97 | state->vertices[4] = -0.5f; | ||
98 | state->vertices[5] = 0.0f; | ||
99 | state->vertices[6] = 0.0f; | ||
100 | state->vertices[7] = 0.5f; | ||
101 | state->vertices[8] = 0.0f; | ||
102 | |||
103 | // Initialize Vertex Buffer Object (VBO) and Vertex Array Object (VAO). | ||
104 | u32 VBO; | ||
105 | glGenBuffers(1, &VBO); | ||
106 | u32 VAO; | ||
107 | glGenVertexArrays(1, &VAO); | ||
108 | |||
109 | // Bind the VAO before any other binding. | ||
110 | glBindVertexArray(VAO); | ||
111 | |||
112 | // Send vertex data to VBO. | ||
113 | glBindBuffer(GL_ARRAY_BUFFER, VBO); | ||
114 | glBufferData(GL_ARRAY_BUFFER, sizeof(state->vertices), state->vertices, | ||
115 | GL_STATIC_DRAW); | ||
116 | |||
117 | // Set vertex attribute pointers. | ||
118 | glEnableVertexAttribArray(0); | ||
119 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); | ||
120 | |||
121 | // Compile shader program. | ||
122 | const char *vert = "shaders/triangle.vert"; | ||
123 | const char *frag = "shaders/triangle.frag"; | ||
124 | if (!compile_shaders(vert, frag, &state->shader_program, platform)) { | ||
125 | platform.log("WARNING: failed to compile shader program"); | ||
126 | } | ||
127 | |||
36 | // Initialize application state. | 128 | // Initialize application state. |
37 | state->window = window; | 129 | state->window = window; |
130 | state->VBO = VBO; | ||
131 | state->VAO = VAO; | ||
132 | |||
38 | return true; | 133 | return true; |
39 | } | 134 | } |
40 | 135 | ||
@@ -46,8 +141,12 @@ app_destroy(AppState *state, PlatformAPI platform) { | |||
46 | 141 | ||
47 | static inline void | 142 | static inline void |
48 | app_reload(AppState *state, PlatformAPI platform) { | 143 | app_reload(AppState *state, PlatformAPI platform) { |
49 | (void)state; // Unused parameter. | ||
50 | platform.log("RELOAD"); | 144 | platform.log("RELOAD"); |
145 | const char *vert = "shaders/triangle.vert"; | ||
146 | const char *frag = "shaders/triangle.frag"; | ||
147 | if (!compile_shaders(vert, frag, &state->shader_program, platform)) { | ||
148 | platform.log("WARNING: failed to compile shader program"); | ||
149 | } | ||
51 | } | 150 | } |
52 | 151 | ||
53 | static inline void | 152 | static inline void |
@@ -58,13 +157,13 @@ app_unload(AppState *state, PlatformAPI platform) { | |||
58 | 157 | ||
59 | static inline bool | 158 | static inline bool |
60 | app_step(AppState *state, PlatformAPI platform) { | 159 | app_step(AppState *state, PlatformAPI platform) { |
61 | (void)platform; // Unused parameter. | 160 | (void)platform; // Unused parameter |
62 | if (glfwWindowShouldClose(state->window)) { | ||
63 | return false; | ||
64 | } | ||
65 | 161 | ||
66 | glClearColor(1.0f, 0.0f, 0.4f, 1.0f); | 162 | glClearColor(0.8f, 0.0f, 0.4f, 1.0f); |
67 | glClear(GL_COLOR_BUFFER_BIT); | 163 | glClear(GL_COLOR_BUFFER_BIT); |
164 | glUseProgram(state->shader_program); | ||
165 | glBindVertexArray(state->VAO); | ||
166 | glDrawArrays(GL_TRIANGLES, 0, 3); | ||
68 | 167 | ||
69 | glfwSwapBuffers(state->window); | 168 | glfwSwapBuffers(state->window); |
70 | glfwPollEvents(); | 169 | glfwPollEvents(); |
@@ -10,6 +10,10 @@ | |||
10 | typedef struct AppState { | 10 | typedef struct AppState { |
11 | // OpenGL | 11 | // OpenGL |
12 | GLFWwindow *window; | 12 | GLFWwindow *window; |
13 | f32 vertices[12]; | ||
14 | u32 VBO; | ||
15 | u32 VAO; | ||
16 | u32 shader_program; | ||
13 | } AppState; | 17 | } AppState; |
14 | 18 | ||
15 | // Function pointers for the AppAPI. | 19 | // Function pointers for the AppAPI. |