summaryrefslogtreecommitdiffstats
path: root/gl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl.c')
-rw-r--r--gl.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/gl.c b/gl.c
new file mode 100644
index 0000000..38c44a5
--- /dev/null
+++ b/gl.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+#include "gl.h"
+#include "balls.h"
+#include "config.h"
+#include "sysfatal.h"
+
+#define VERTEX_SHADER "balls.vert"
+#define FRAGMENT_SHADER "balls.frag"
+
+static void initShaders(void);
+static void compileShader(GLint shader);
+static void genVertexBuffer(GLuint *vertexVBO, int nBalls);
+static void genColorBuffer(GLuint *colorVBO, int nBalls);
+
+void
+initGL(int argc, char *argv[]) {
+ GLenum err;
+
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
+ glutInitWindowSize(WIDTH, HEIGHT);
+ glutCreateWindow(WINDOW_TITLE);
+ glClearColor(1, 1, 1, 1);
+
+ if ((err = glewInit()) != GLEW_OK)
+ sysfatal("Failed to initialize GLEW.\n");
+
+ initShaders();
+}
+
+/* Create GL vertex and color buffers. */
+void
+genBuffers(GLuint *vertexVAO, GLuint *vertexVBO, GLuint *colorVBO, int nBalls) {
+ glGenVertexArrays(1, vertexVAO);
+ glBindVertexArray(*vertexVAO);
+ genVertexBuffer(vertexVBO, nBalls);
+ genColorBuffer(colorVBO, nBalls);
+}
+
+void
+freeGL(GLuint vertexVAO, GLuint vertexVBO, GLuint colorVBO) {
+ glDeleteBuffers(1, &vertexVBO);
+ glDeleteBuffers(1, &vertexVAO);
+ glDeleteBuffers(1, &colorVBO);
+}
+
+static void
+initShaders(void) {
+ GLuint vs, fs, prog;
+ int err;
+ char *vSrc, *fSrc;
+ size_t vLen, fLen;
+
+ vs = glCreateShader(GL_VERTEX_SHADER);
+ fs = glCreateShader(GL_FRAGMENT_SHADER);
+
+ err = readFile(VERTEX_SHADER, &vSrc, &vLen);
+ if (err != 0)
+ sysfatal("Failed to read '%s'\n", VERTEX_SHADER);
+ err = readFile(FRAGMENT_SHADER, &fSrc, &fLen);
+ if (err != 0)
+ sysfatal("Failed to read '%s'\n", FRAGMENT_SHADER);
+
+ glShaderSource(vs, 1, (const char **) &vSrc, (GLint *) &vLen);
+ glShaderSource(fs, 1, (const char **) &fSrc, (GLint *) &fLen);
+
+ compileShader(vs);
+ compileShader(fs);
+
+ free(vSrc);
+ free(fSrc);
+
+ prog = glCreateProgram();
+
+ glBindAttribLocation(prog, 0, "in_coords");
+ glBindAttribLocation(prog, 1, "in_colors");
+
+ glAttachShader(prog, vs);
+ glAttachShader(prog, fs);
+
+ glLinkProgram(prog);
+ glUseProgram(prog);
+}
+
+static void
+compileShader(GLint shader) {
+ GLint success;
+ GLsizei logSize;
+ GLchar *log;
+
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
+ if ((log = malloc((logSize+1) * sizeof(GLchar))) == NULL)
+ sysfatal("Failed to allocate space for shader compile log.\n");
+ glGetShaderInfoLog(shader, logSize+1, NULL, log);
+ log[logSize] = '\0';
+ fprintf(stderr, "%s\n", log);
+ free(log);
+ exit(1);
+ }
+}
+
+static void
+genVertexBuffer(GLuint *vertexVBO, int nBalls) {
+ glGenBuffers(1, vertexVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, *vertexVBO);
+ glBufferData(GL_ARRAY_BUFFER, nBalls*CIRCLE_POINTS*2*sizeof(GLfloat), NULL, GL_DYNAMIC_DRAW);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ glEnableVertexAttribArray(0);
+}
+
+static void
+genColorBuffer(GLuint *colorVBO, int nBalls) {
+ GLfloat (*colors)[3];
+ GLfloat color[3];
+ int i, j;
+
+ if ((colors = malloc(nBalls*CIRCLE_POINTS*3*sizeof(GLfloat))) == NULL)
+ sysfatal("Failed to allocate color array.\n");
+ for (i = 0; i < nBalls; i++) {
+ color[0] = randFloat(0, 1);
+ color[1] = randFloat(0, 1);
+ color[2] = randFloat(0, 1);
+ for (j = 0; j < CIRCLE_POINTS; j++) {
+ colors[i*CIRCLE_POINTS + j][0] = color[0];
+ colors[i*CIRCLE_POINTS + j][1] = color[1];
+ colors[i*CIRCLE_POINTS + j][2] = color[2];
+ }
+ }
+
+ glGenBuffers(1, colorVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, *colorVBO);
+ glBufferData(GL_ARRAY_BUFFER, nBalls*CIRCLE_POINTS*3*sizeof(GLfloat), colors, GL_STATIC_DRAW);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ glEnableVertexAttribArray(1);
+
+ free(colors);
+}