summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Sanchez Brotons <alex@alexsb.xyz>2022-08-20 11:13:29 +0200
committerAlex Sanchez Brotons <alex@alexsb.xyz>2022-08-20 11:13:29 +0200
commita11a4738f7b2c09001b1328b12f8022a3d635ecd (patch)
treef534a14dc74bcd1787dc540d175366a16881b8a6
downloadogl-monotext-a11a4738f7b2c09001b1328b12f8022a3d635ecd.tar.gz
ogl-monotext-a11a4738f7b2c09001b1328b12f8022a3d635ecd.zip
Initial commit
Setting up a build process for a macOS OpenGL application.
-rw-r--r--.gitignore1
-rw-r--r--Makefile56
-rw-r--r--src/main.c204
-rwxr-xr-xsrc/shorthand.h27
4 files changed, 288 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..378eac2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
build
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..57c2774
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,56 @@
1.POSIX:
2.SUFFIXES:
3
4# Source code location and files to watch for changes.
5SRC_DIR := src
6BUILD_DIR := build
7SRC_MAIN := $(SRC_DIR)/main.c
8WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h")
9INC_DIRS := $(shell find $(SRC_DIR) -type d)
10INC_FLAGS := $(addprefix -I,$(INC_DIRS))
11
12# Output executable.
13TARGET := ogl
14BIN := $(BUILD_DIR)/$(TARGET)
15
16# Compiler and linker configuration.
17CC := cc
18CFLAGS := -Wall -Wextra -pedantic -DBIN_NAME=\"$(TARGET)\" -Wno-missing-braces
19CFLAGS += $(INC_FLAGS)
20NASM_FLAGS ?= -felf64
21LDFLAGS :=
22LDLIBS := -lglfw -framework OpenGL
23RELEASE_CFLAGS := -DNDEBUG -O2
24DEBUG_CFLAGS := -DDEBUG -O0 -g
25
26.PHONY: build tests clean
27
28# Setup debug/release builds.
29# make clean && make <target> DEBUG=0
30# make clean && make <target> DEBUG=1
31DEBUG ?= 0
32ifeq ($(DEBUG), 1)
33 CFLAGS += $(DEBUG_CFLAGS)
34 NASM_FLAGS += -g -F dwarf
35else ifeq ($(DEBUG), 2)
36 CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address
37 NASM_FLAGS += -g -F dwarf
38else
39 CFLAGS += $(RELEASE_CFLAGS)
40endif
41
42main: $(BIN)
43
44$(BIN): $(SRC_MAIN) $(WATCH_SRC) $(BUILD_DIR)
45 $(CC) $(CFLAGS) $(LDFLAGS) -o $(BIN) $(SRC_MAIN) $(LDLIBS)
46
47# Create build directory if needed.
48$(BUILD_DIR):
49 mkdir -p $(BUILD_DIR)
50
51run: $(BIN)
52 $(BIN) example.bdl
53
54# Remove build directory.
55clean:
56 rm -rf $(BUILD_DIR)
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..b30280a
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,204 @@
1#define GL_SILENCE_DEPRECATION
2#define GLFW_INCLUDE_GLCOREARB
3#include <GLFW/glfw3.h>
4
5#include <stdio.h>
6#include <stdlib.h>
7
8#include "shorthand.h"
9
10//
11// Callbacks.
12//
13
14void
15glfw_error_callback(int error, const char* description) {
16 (void)error;
17 fprintf(stderr, "error: %s\n", description);
18}
19
20void
21glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
22 (void)mods;
23 (void)scancode;
24 if (action == GLFW_PRESS &&
25 (key == GLFW_KEY_ESCAPE || key == GLFW_KEY_CAPS_LOCK)) {
26 glfwSetWindowShouldClose(window, GLFW_TRUE);
27 }
28}
29
30typedef struct Context {
31 GLFWwindow *window;
32 u32 gl_version_major;
33 u32 gl_version_minor;
34 u32 win_width;
35 u32 win_height;
36 char win_title[256];
37 bool win_resizable;
38
39 struct {
40 f64 prev;
41 f64 elapsed;
42 size_t n_frames;
43 } frame_time;
44} Context;
45
46u32
47compile_program(Context *ctx, const char *vert_src, const char *frag_src) {
48 // Compile vertex shader.
49 u32 vert_shader = glCreateShader(GL_VERTEX_SHADER);
50 {
51 glShaderSource(vert_shader, 1, &vert_src, NULL);
52 glCompileShader(vert_shader);
53 int success = 0;
54 glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &success);
55 if (!success) {
56 fprintf(stderr, "error: vertex shader compilation failed\n");
57 glfwDestroyWindow(ctx->window);
58 glfwTerminate();
59 exit(EXIT_FAILURE);
60 }
61 }
62
63 // Compile fragment shader.
64 u32 frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
65 {
66 glShaderSource(frag_shader, 1, &frag_src, NULL);
67 glCompileShader(frag_shader);
68 int success = 0;
69 glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &success);
70 if (!success) {
71 fprintf(stderr, "error: fragment shader compilation failed\n");
72 glfwDestroyWindow(ctx->window);
73 glfwTerminate();
74 exit(EXIT_FAILURE);
75 }
76 }
77
78 // Link shader program.
79 u32 program = glCreateProgram();
80 {
81 glAttachShader(program, vert_shader);
82 glAttachShader(program, frag_shader);
83 glLinkProgram(program);
84 int success = 0;
85 glGetProgramiv(program, GL_LINK_STATUS, &success);
86 if(!success) {
87 fprintf(stderr, "error: program shader linking failed\n");
88 glfwDestroyWindow(ctx->window);
89 glfwTerminate();
90 exit(EXIT_FAILURE);
91 }
92 }
93
94 // Delete unused objects.
95 glDeleteShader(vert_shader);
96 glDeleteShader(frag_shader);
97 return program;
98}
99
100void
101init_context(Context *ctx) {
102 if (!glfwInit()) {
103 fprintf(stderr, "error: GLFW initialization failed");
104 exit(EXIT_FAILURE);
105 }
106
107 // Init window and OpenGL context.
108 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, ctx->gl_version_major);
109 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, ctx->gl_version_minor);
110 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
111 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
112 glfwWindowHint(GLFW_RESIZABLE, ctx->win_resizable);
113 GLFWwindow* window = glfwCreateWindow(
114 ctx->win_width, ctx->win_height, ctx->win_title, NULL, NULL);
115 if (!window) {
116 fprintf(stderr, "error: couldn't open OpenGL window");
117 glfwTerminate();
118 exit(EXIT_FAILURE);
119 }
120
121 // Enable current OpenGL context and init GLAD.
122 glfwMakeContextCurrent(window);
123 // TODO: Working on macOS for now, need to check if this is needed.
124 // if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
125 // fprintf(stderr, "error: GLAD initialization failed");
126 // glfwDestroyWindow(window);
127 // glfwTerminate();
128 // exit(EXIT_FAILURE);
129 // }
130
131 ctx->window = window;
132}
133
134void
135setup_callbacks(Context *ctx) {
136 glfwSetErrorCallback(glfw_error_callback);
137 glfwSetKeyCallback(ctx->window, glfw_key_callback);
138}
139
140void
141update_frame_time(Context *ctx) {
142 // Measure frame times and fps.
143 f64 cur_time = glfwGetTime();
144 f64 delta_time = cur_time - ctx->frame_time.prev;
145 ctx->frame_time.elapsed += delta_time;
146 ctx->frame_time.n_frames++;
147 if (ctx->frame_time.elapsed >= 1.0) {
148 f64 fps = 0;
149 fps = ctx->frame_time.n_frames / ctx->frame_time.elapsed;
150 ctx->frame_time.elapsed = 0;
151 ctx->frame_time.n_frames = 0;
152
153 // Update title with timing data.
154 char title_buf[256 * 2];
155 sprintf(title_buf,
156 "%s [%.2fms, %.2f FPS]",
157 ctx->win_title, delta_time * 1000, fps);
158 glfwSetWindowTitle(ctx->window, title_buf);
159 }
160 ctx->frame_time.prev = cur_time;
161}
162
163void
164update(Context *ctx) {
165 update_frame_time(ctx);
166}
167
168void
169render(Context *ctx) {
170 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
171 glfwSwapBuffers(ctx->window);
172}
173
174int
175main(void) {
176 Context ctx = (Context){
177 .gl_version_major = 3,
178 .gl_version_minor = 2,
179 .win_width = 800,
180 .win_height = 600,
181 .win_title = "OpenGL experiments",
182 };
183 init_context(&ctx);
184 setup_callbacks(&ctx);
185
186 //
187 // Main loop.
188 //
189
190 ctx.frame_time.prev = glfwGetTime();
191 ctx.frame_time.elapsed = 0;
192 ctx.frame_time.n_frames = 0;
193 while (!glfwWindowShouldClose(ctx.window)) {
194 update(&ctx);
195 render(&ctx);
196 glfwPollEvents(); // constant updates.
197 // glfwWaitEvents(); // updates only when input arrives (better cpu usage).
198 }
199
200 glfwDestroyWindow(ctx.window);
201 glfwTerminate();
202 return EXIT_SUCCESS;
203}
204
diff --git a/src/shorthand.h b/src/shorthand.h
new file mode 100755
index 0000000..b5174a1
--- /dev/null
+++ b/src/shorthand.h
@@ -0,0 +1,27 @@
1#ifndef SHORTHAND_H
2#define SHORTHAND_H
3
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7
8typedef uint8_t u8;
9typedef uint16_t u16;
10typedef uint32_t u32;
11typedef uint64_t u64;
12typedef int8_t s8;
13typedef int16_t s16;
14typedef int32_t s32;
15typedef int64_t s64;
16typedef volatile u8 vu8;
17typedef volatile u16 vu16;
18typedef volatile u32 vu32;
19typedef volatile u64 vu64;
20typedef volatile s8 vs8;
21typedef volatile s16 vs16;
22typedef volatile s32 vs32;
23typedef volatile s64 vs64;
24typedef float f32;
25typedef double f64;
26
27#endif // SHORTHAND_H