├── .gitignore ├── LICENSE ├── Makefile ├── shaders ├── fragment.glsl └── vertex.glsl └── src ├── main.c ├── matrix.c ├── matrix.h ├── shader.c ├── shader.h ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | main 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014 Michael Fogleman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC = src 2 | BUILD = build 3 | FLAGS = -std=c99 -O3 4 | LIBS = -lglew -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo 5 | OBJ = $(patsubst $(SRC)/%.c,$(BUILD)/%.o,$(wildcard $(SRC)/*.c)) 6 | INC = $(wildcard src/*.h) 7 | 8 | all: $(BUILD) main 9 | 10 | run: all 11 | ./main 12 | 13 | clean: 14 | rm -Rf $(BUILD) 15 | rm main 16 | 17 | $(BUILD): 18 | mkdir -p $@ 19 | 20 | $(BUILD)/%.o: $(SRC)/%.c ${INC} 21 | gcc -c -o $@ $(FLAGS) $< 22 | 23 | main: $(OBJ) 24 | gcc -o $@ $^ $(CFLAGS) $(LIBS) 25 | -------------------------------------------------------------------------------- /shaders/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | void main() { 4 | gl_FragColor = vec4(1.0); 5 | } 6 | -------------------------------------------------------------------------------- /shaders/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform mat4 matrix; 4 | 5 | attribute vec4 position; 6 | 7 | void main() { 8 | gl_Position = matrix * position; 9 | } 10 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "matrix.h" 4 | #include "shader.h" 5 | #include "util.h" 6 | 7 | int main(void) { 8 | if (!glfwInit()) { 9 | return -1; 10 | } 11 | 12 | GLFWwindow *window = glfwCreateWindow(800, 800, "HelloGL", NULL, NULL); 13 | if (!window) { 14 | glfwTerminate(); 15 | return -1; 16 | } 17 | 18 | glfwMakeContextCurrent(window); 19 | glEnable(GL_DEPTH_TEST); 20 | 21 | if (glewInit() != GLEW_OK) { 22 | glfwTerminate(); 23 | return -1; 24 | } 25 | 26 | GLuint program = load_program( 27 | "shaders/vertex.glsl", "shaders/fragment.glsl"); 28 | GLuint position = glGetAttribLocation(program, "position"); 29 | GLuint matrix = glGetUniformLocation(program, "matrix"); 30 | 31 | float data[] = { 32 | -0.5, -0.5, 33 | 0.5, -0.5, 34 | 0, 0.5 35 | }; 36 | GLuint buffer = gen_buffer(sizeof(data), data); 37 | 38 | while (!glfwWindowShouldClose(window)) { 39 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 40 | 41 | float mat[16]; 42 | mat_identity(mat); 43 | mat_translate(mat, 0, -0.5, 0); 44 | mat_rotate(mat, 0, 0, 1, glfwGetTime()); 45 | mat_ortho(mat, -2, 2, -2, 2, -2, 2); 46 | 47 | glUseProgram(program); 48 | glUniformMatrix4fv(matrix, 1, GL_FALSE, mat); 49 | glBindBuffer(GL_ARRAY_BUFFER, buffer); 50 | glEnableVertexAttribArray(position); 51 | glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0); 52 | glDrawArrays(GL_TRIANGLES, 0, 3); 53 | glDisableVertexAttribArray(position); 54 | glBindBuffer(GL_ARRAY_BUFFER, 0); 55 | 56 | glfwSwapBuffers(window); 57 | glfwPollEvents(); 58 | } 59 | 60 | glfwTerminate(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "matrix.h" 3 | 4 | void vec_normalize(float *x, float *y, float *z) { 5 | float d = sqrtf((*x) * (*x) + (*y) * (*y) + (*z) * (*z)); 6 | *x /= d; *y /= d; *z /= d; 7 | } 8 | 9 | void mat_identity(float *matrix) { 10 | matrix[0] = 1; 11 | matrix[1] = 0; 12 | matrix[2] = 0; 13 | matrix[3] = 0; 14 | matrix[4] = 0; 15 | matrix[5] = 1; 16 | matrix[6] = 0; 17 | matrix[7] = 0; 18 | matrix[8] = 0; 19 | matrix[9] = 0; 20 | matrix[10] = 1; 21 | matrix[11] = 0; 22 | matrix[12] = 0; 23 | matrix[13] = 0; 24 | matrix[14] = 0; 25 | matrix[15] = 1; 26 | } 27 | 28 | void mat_translate(float *matrix, float dx, float dy, float dz) { 29 | float mat[16]; 30 | mat[0] = 1; 31 | mat[1] = 0; 32 | mat[2] = 0; 33 | mat[3] = 0; 34 | mat[4] = 0; 35 | mat[5] = 1; 36 | mat[6] = 0; 37 | mat[7] = 0; 38 | mat[8] = 0; 39 | mat[9] = 0; 40 | mat[10] = 1; 41 | mat[11] = 0; 42 | mat[12] = dx; 43 | mat[13] = dy; 44 | mat[14] = dz; 45 | mat[15] = 1; 46 | mat_multiply(matrix, mat, matrix); 47 | } 48 | 49 | void mat_rotate(float *matrix, float x, float y, float z, float angle) { 50 | vec_normalize(&x, &y, &z); 51 | float s = sinf(angle); 52 | float c = cosf(angle); 53 | float m = 1 - c; 54 | float mat[16]; 55 | mat[0] = m * x * x + c; 56 | mat[1] = m * x * y - z * s; 57 | mat[2] = m * z * x + y * s; 58 | mat[3] = 0; 59 | mat[4] = m * x * y + z * s; 60 | mat[5] = m * y * y + c; 61 | mat[6] = m * y * z - x * s; 62 | mat[7] = 0; 63 | mat[8] = m * z * x - y * s; 64 | mat[9] = m * y * z + x * s; 65 | mat[10] = m * z * z + c; 66 | mat[11] = 0; 67 | mat[12] = 0; 68 | mat[13] = 0; 69 | mat[14] = 0; 70 | mat[15] = 1; 71 | mat_multiply(matrix, mat, matrix); 72 | } 73 | 74 | void mat_vec_multiply(float *vector, float *a, float *b) { 75 | float result[4]; 76 | for (int i = 0; i < 4; i++) { 77 | float total = 0; 78 | for (int j = 0; j < 4; j++) { 79 | int p = j * 4 + i; 80 | int q = j; 81 | total += a[p] * b[q]; 82 | } 83 | result[i] = total; 84 | } 85 | for (int i = 0; i < 4; i++) { 86 | vector[i] = result[i]; 87 | } 88 | } 89 | 90 | void mat_multiply(float *matrix, float *a, float *b) { 91 | float result[16]; 92 | for (int c = 0; c < 4; c++) { 93 | for (int r = 0; r < 4; r++) { 94 | int index = c * 4 + r; 95 | float total = 0; 96 | for (int i = 0; i < 4; i++) { 97 | int p = i * 4 + r; 98 | int q = c * 4 + i; 99 | total += a[p] * b[q]; 100 | } 101 | result[index] = total; 102 | } 103 | } 104 | for (int i = 0; i < 16; i++) { 105 | matrix[i] = result[i]; 106 | } 107 | } 108 | 109 | void mat_apply(float *data, float *matrix, int count, int offset, int stride) { 110 | float vec[4] = {0, 0, 0, 1}; 111 | for (int i = 0; i < count; i++) { 112 | float *d = data + offset + stride * i; 113 | vec[0] = *(d++); vec[1] = *(d++); vec[2] = *(d++); 114 | mat_vec_multiply(vec, matrix, vec); 115 | d = data + offset + stride * i; 116 | *(d++) = vec[0]; *(d++) = vec[1]; *(d++) = vec[2]; 117 | } 118 | } 119 | 120 | void frustum_planes( 121 | float planes[6][4], float *matrix, float znear, float zfar) 122 | { 123 | float *m = matrix; 124 | planes[0][0] = m[3] + m[0]; 125 | planes[0][1] = m[7] + m[4]; 126 | planes[0][2] = m[11] + m[8]; 127 | planes[0][3] = m[15] + m[12]; 128 | planes[1][0] = m[3] - m[0]; 129 | planes[1][1] = m[7] - m[4]; 130 | planes[1][2] = m[11] - m[8]; 131 | planes[1][3] = m[15] - m[12]; 132 | planes[2][0] = m[3] + m[1]; 133 | planes[2][1] = m[7] + m[5]; 134 | planes[2][2] = m[11] + m[9]; 135 | planes[2][3] = m[15] + m[13]; 136 | planes[3][0] = m[3] - m[1]; 137 | planes[3][1] = m[7] - m[5]; 138 | planes[3][2] = m[11] - m[9]; 139 | planes[3][3] = m[15] - m[13]; 140 | planes[4][0] = znear * m[3] + m[2]; 141 | planes[4][1] = znear * m[7] + m[6]; 142 | planes[4][2] = znear * m[11] + m[10]; 143 | planes[4][3] = znear * m[15] + m[14]; 144 | planes[5][0] = zfar * m[3] - m[2]; 145 | planes[5][1] = zfar * m[7] - m[6]; 146 | planes[5][2] = zfar * m[11] - m[10]; 147 | planes[5][3] = zfar * m[15] - m[14]; 148 | } 149 | 150 | void mat_frustum( 151 | float *matrix, float left, float right, float bottom, 152 | float top, float znear, float zfar) 153 | { 154 | float temp1, temp2, temp3, temp4; 155 | temp1 = 2.0 * znear; 156 | temp2 = right - left; 157 | temp3 = top - bottom; 158 | temp4 = zfar - znear; 159 | float mat[16]; 160 | mat[0] = temp1 / temp2; 161 | mat[1] = 0.0; 162 | mat[2] = 0.0; 163 | mat[3] = 0.0; 164 | mat[4] = 0.0; 165 | mat[5] = temp1 / temp3; 166 | mat[6] = 0.0; 167 | mat[7] = 0.0; 168 | mat[8] = (right + left) / temp2; 169 | mat[9] = (top + bottom) / temp3; 170 | mat[10] = (-zfar - znear) / temp4; 171 | mat[11] = -1.0; 172 | mat[12] = 0.0; 173 | mat[13] = 0.0; 174 | mat[14] = (-temp1 * zfar) / temp4; 175 | mat[15] = 0.0; 176 | mat_multiply(matrix, mat, matrix); 177 | } 178 | 179 | void mat_perspective( 180 | float *matrix, float fov, float aspect, 181 | float znear, float zfar) 182 | { 183 | float ymax, xmax; 184 | ymax = znear * tanf(fov * M_PI / 360.0); 185 | xmax = ymax * aspect; 186 | mat_frustum(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); 187 | } 188 | 189 | void mat_ortho( 190 | float *matrix, 191 | float left, float right, float bottom, float top, float near, float far) 192 | { 193 | float mat[16]; 194 | mat[0] = 2 / (right - left); 195 | mat[1] = 0; 196 | mat[2] = 0; 197 | mat[3] = 0; 198 | mat[4] = 0; 199 | mat[5] = 2 / (top - bottom); 200 | mat[6] = 0; 201 | mat[7] = 0; 202 | mat[8] = 0; 203 | mat[9] = 0; 204 | mat[10] = -2 / (far - near); 205 | mat[11] = 0; 206 | mat[12] = -(right + left) / (right - left); 207 | mat[13] = -(top + bottom) / (top - bottom); 208 | mat[14] = -(far + near) / (far - near); 209 | mat[15] = 1; 210 | mat_multiply(matrix, mat, matrix); 211 | } 212 | -------------------------------------------------------------------------------- /src/matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef _matrix_h_ 2 | #define _matrix_h_ 3 | 4 | void vec_normalize(float *x, float *y, float *z); 5 | void mat_identity(float *matrix); 6 | void mat_translate(float *matrix, float dx, float dy, float dz); 7 | void mat_rotate(float *matrix, float x, float y, float z, float angle); 8 | void mat_vec_multiply(float *vector, float *a, float *b); 9 | void mat_multiply(float *matrix, float *a, float *b); 10 | void mat_apply(float *data, float *matrix, int count, int offset, int stride); 11 | void frustum_planes( 12 | float planes[6][4], float *matrix, float znear, float zfar); 13 | void mat_frustum( 14 | float *matrix, float left, float right, float bottom, 15 | float top, float znear, float zfar); 16 | void mat_perspective( 17 | float *matrix, float fov, float aspect, 18 | float near, float far); 19 | void mat_ortho( 20 | float *matrix, 21 | float left, float right, float bottom, float top, float near, float far); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/shader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "shader.h" 4 | 5 | char *load_file(const char *path) { 6 | FILE *file = fopen(path, "rb"); 7 | fseek(file, 0, SEEK_END); 8 | int length = ftell(file); 9 | rewind(file); 10 | char *data = calloc(length + 1, sizeof(char)); 11 | fread(data, 1, length, file); 12 | fclose(file); 13 | return data; 14 | } 15 | 16 | GLuint make_shader(GLenum type, const char *source) { 17 | GLuint shader = glCreateShader(type); 18 | glShaderSource(shader, 1, &source, NULL); 19 | glCompileShader(shader); 20 | GLint status; 21 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 22 | if (status == GL_FALSE) { 23 | GLint length; 24 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); 25 | GLchar *info = calloc(length, sizeof(GLchar)); 26 | glGetShaderInfoLog(shader, length, NULL, info); 27 | fprintf(stderr, "glCompileShader failed:\n%s\n", info); 28 | free(info); 29 | } 30 | return shader; 31 | } 32 | 33 | GLuint load_shader(GLenum type, const char *path) { 34 | char *data = load_file(path); 35 | GLuint result = make_shader(type, data); 36 | free(data); 37 | return result; 38 | } 39 | 40 | GLuint make_program(GLuint shader1, GLuint shader2) { 41 | GLuint program = glCreateProgram(); 42 | glAttachShader(program, shader1); 43 | glAttachShader(program, shader2); 44 | glLinkProgram(program); 45 | GLint status; 46 | glGetProgramiv(program, GL_LINK_STATUS, &status); 47 | if (status == GL_FALSE) { 48 | GLint length; 49 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); 50 | GLchar *info = calloc(length, sizeof(GLchar)); 51 | glGetProgramInfoLog(program, length, NULL, info); 52 | fprintf(stderr, "glLinkProgram failed: %s\n", info); 53 | free(info); 54 | } 55 | glDetachShader(program, shader1); 56 | glDetachShader(program, shader2); 57 | glDeleteShader(shader1); 58 | glDeleteShader(shader2); 59 | return program; 60 | } 61 | 62 | GLuint load_program(const char *path1, const char *path2) { 63 | GLuint shader1 = load_shader(GL_VERTEX_SHADER, path1); 64 | GLuint shader2 = load_shader(GL_FRAGMENT_SHADER, path2); 65 | GLuint program = make_program(shader1, shader2); 66 | return program; 67 | } 68 | -------------------------------------------------------------------------------- /src/shader.h: -------------------------------------------------------------------------------- 1 | #ifndef _shader_h_ 2 | #define _shader_h_ 3 | 4 | #include 5 | #include 6 | 7 | GLuint make_shader(GLenum type, const char *source); 8 | GLuint load_shader(GLenum type, const char *path); 9 | GLuint make_program(GLuint shader1, GLuint shader2); 10 | GLuint load_program(const char *path1, const char *path2); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | GLuint gen_buffer(GLsizei size, GLfloat *data) { 4 | GLuint buffer; 5 | glGenBuffers(1, &buffer); 6 | glBindBuffer(GL_ARRAY_BUFFER, buffer); 7 | glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); 8 | glBindBuffer(GL_ARRAY_BUFFER, 0); 9 | return buffer; 10 | } 11 | 12 | void del_buffer(GLuint buffer) { 13 | glDeleteBuffers(1, &buffer); 14 | } 15 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _util_h_ 2 | #define _util_h_ 3 | 4 | #include 5 | #include 6 | 7 | GLuint gen_buffer(GLsizei size, GLfloat *data); 8 | void del_buffer(GLuint buffer); 9 | 10 | #endif 11 | --------------------------------------------------------------------------------