summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKamil Kaminski <kamilkss@gmail.com>2011-08-09 22:25:44 -0500
committerKamil Kaminski <kamilkss@gmail.com>2011-08-09 22:25:44 -0500
commit157f167983a734c59e2e512905f654c44ced68a7 (patch)
tree4f3fc2cb5fac6eacc266a67fb0fa099a7cc3c098
downloadglshader2.1-157f167983a734c59e2e512905f654c44ced68a7.tar.gz
glshader2.1-157f167983a734c59e2e512905f654c44ced68a7.tar.bz2
glshader2.1-157f167983a734c59e2e512905f654c44ced68a7.zip
initial commit
-rw-r--r--Makefile25
-rw-r--r--mingw3245
-rw-r--r--shader.c720
3 files changed, 790 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3774e47
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+PROG = shader
+OBJS = $(PROG).o
+CC = gcc
+DBGFLAGS = -g -O0
+ifdef DEBUG
+ CFLAGS = $(DBGFLAGS) -Wall -std=c99
+else
+ CFLAGS = -Wall -std=c99 -O2 -march=native -mtune=native
+endif
+LDFLAGS = -lGLEW -lGL -lGLU -lm -lglut
+SDL_CFLAGS := $(shell sdl-config --cflags)
+SDL_LDFLAGS := $(shell sdl-config --libs)
+SDL_image_CFLAGS := $(shell pkg-config --cflags SDL_image)
+SDL_image_LDFLAGS := $(shell pkg-config --libs SDL_image)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) $(SDL_LDFLAGS) $(SDL_image_LDFLAGS) $(OBJS) -o $(PROG)
+
+$(PROG).o: $(PROG).c
+ $(CC) -c $(CFLAGS) $(SDL_CFLAGS) $(SDL_image_CFLAGS) $(PROG).c
+
+.PHONY: clean
+
+clean:
+ rm -f *.o ./$(PROG)
diff --git a/mingw32 b/mingw32
new file mode 100644
index 0000000..0f6649f
--- /dev/null
+++ b/mingw32
@@ -0,0 +1,45 @@
+BIN = shader
+SRC = shader.c
+CC = gcc
+CFLAGS = -Wall -std=c99 -MD
+DBGFLAGS = -g -O0
+ifdef DEBUG
+ CFLAGS += $(DBGFLAGS)
+else
+ CFLAGS += -O2 -march=native -mtune=native
+endif
+LDFLAGS = -lglew32 -lopengl32 -lglu32 -lm -lfreeglut -lmingw32 -lsdlmain -lsdl \
+ -lsdl_image -mwindows
+
+OBJ_DIR = obj
+DEPS_DIR = obj
+BIN_DIR = .
+
+C_FILES = $(filter %.c, $(SRC))
+DEP_FILES = $(addprefix $(DEPS_DIR)\, $(addsuffix .d, $(notdir $(subst .c,,$(SRC)))))
+OBJ_FILES = $(addprefix $(OBJ_DIR)\, $(addsuffix .o, $(notdir $(subst .c,,$(SRC)))))
+
+INCL = -I/include
+
+define C_template
+$(1): $(2)
+ @mkdir -p $$(OBJ_DIR)
+ @mkdir -p $$(DEPS_DIR)
+ $$(CC) -c $$(CFLAGS) $$(INCL) $$< -o $$@
+endef
+
+all: $(BIN)
+
+$(foreach cfile, $(C_FILES), $(eval $(call C_template, $(OBJ_DIR)\$(notdir $(subst .c,,$(cfile))).o, $(cfile))))
+
+$(BIN): $(OBJ_FILES)
+ @mkdir -p $(BIN_DIR)
+ $(CC) -o $(BIN_DIR)/$@ $(OBJ_FILES) $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf $(OBJ_DIR)
+ rm -f $(BIN_DIR)/$(BIN).exe stdout.txt stderr.txt
+
+-include $(DEP_FILES)
diff --git a/shader.c b/shader.c
new file mode 100644
index 0000000..60b9a11
--- /dev/null
+++ b/shader.c
@@ -0,0 +1,720 @@
+/* shader.c
+ *
+ * Kamil Kaminski
+ * kkaminsk.com
+ *
+ * Example of using a VBO with programmable pipeline on OpenGL 2.1
+ *
+ *
+ */
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <GL/glew.h>
+#include <GL/freeglut.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+
+/* for simplicity we pack */
+/* this structure represents a point with attributes */
+#pragma pack(1)
+typedef struct gltpoint
+{
+ GLfloat normal[3];
+ GLfloat texcoord[2];
+ GLubyte color[3];
+} gltpoint_t;
+#pragma pack()
+
+/* globals */
+int program_running = 1;
+SDL_Surface *screen;
+GLuint buffer_objects[3];
+
+const GLchar vshader[] =
+ "void main(void)\n"
+ "{\n"
+ " // normal MVP transform\n"
+ " vec4 clipCoord = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ " gl_Position = clipCoord;\n"
+ "\n"
+ " // Copy the primary color\n"
+ " gl_FrontColor = gl_Color;\n"
+ "\n"
+ " // Calculate NDC\n"
+ " vec4 ndc = vec4(clipCoord.xyz, 0) / clipCoord.w;\n"
+ "\n"
+ " // Map from [-1,1] to [0,1] before outputting\n"
+ " gl_FrontSecondaryColor = (ndc * 0.5) + 0.5;\n"
+ "}\n";
+
+const GLchar fshader[] =
+ "uniform float flickerFactor;\n"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " // Mix primary and secondary colors, 50/50\n"
+ " vec4 temp = mix(gl_Color, vec4(vec3(gl_SecondaryColor), 1.0), 0.5);\n"
+ "\n"
+ " // Multiply by flicker factor\n"
+ " gl_FragColor = temp * flickerFactor;\n"
+ "}\n";
+
+/* few light arrays */
+const GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+const GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
+const GLfloat fMedLight[] = { 0.50f, 0.50f, 0.50f, 1.0f };
+const GLfloat fShinyLight[] = { 0.70f, 0.70f, 0.70f, 1.0f };
+const GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+
+/* light values and coordinates */
+const GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f };
+
+struct
+{
+ GLuint prog, vert, frag;
+} p;
+
+/* function prototypes */
+static size_t loadfile_to_mem(char *, char **);
+static int vertprog_create(GLuint *, const char *);
+static int fragprog_create(GLuint *, const char *);
+static int prog_create(GLuint *, GLuint *, GLuint *);
+static int gltGenVBOInterleaved(GLuint *, float *, float *, float *,
+ unsigned char *, unsigned short *, GLsizeiptr, GLsizeiptr);
+static int gltDrawVBOInterleaved(GLuint *, size_t, GLenum);
+static void gl_error_check(const char *, const char *, const int);
+static void resize(int, int);
+static void keys(SDL_keysym *, unsigned int *);
+static void process_events(void);
+static void render(void);
+static void setup_sdl(void);
+static void setup_glew(void);
+static void setup_opengl(void);
+static void dump_shaders(void);
+
+/* populates param memory with content of the file param fname */
+static size_t loadfile_to_mem(char *fname, char **memory)
+{
+ if (!fname || !memory)
+ return 0;
+
+ size_t bytes = 0;
+ FILE *file = fopen(fname, "rt");
+
+ if (file != NULL)
+ {
+ fseek(file, 0, SEEK_END);
+ size_t end = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ *memory = (char *) malloc(sizeof(char) * end);
+ if (!memory)
+ {
+ fprintf(stderr, "%s failed, %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+ perror("malloc");
+ fclose(file);
+ return 0;
+ }
+
+ bytes = fread(*memory, sizeof(char), end, file);
+ fclose(file);
+ }
+ else
+ {
+ fprintf(stderr, "%s: failed to open \"%s\", %s:%d\n",
+ __FUNCTION__, fname, __FILE__, __LINE__);
+ perror("fopen");
+ }
+
+ return bytes;
+}
+
+/* we have a separate buffer objects for vertex data, attributes, and indices
+ * interleaved arrays improve cache performance, the key is locality
+ * for simplicity, vertex is composed of 3 components and texcoord of 2 components
+ */
+static int gltGenVBOInterleaved(GLuint *bufferobjects, float *vert_arr,
+ float *texcoord_arr, float *norm_arr, unsigned char *color_arr,
+ unsigned short *indices_arr, GLsizeiptr points_n, GLsizeiptr indices_n)
+{
+ if (!bufferobjects || !vert_arr || !texcoord_arr || !norm_arr || !color_arr ||
+ !indices_arr || !points_n || !indices_n)
+ return -1;
+
+ /* create an interleaved data structure, is it worth the cpu time? */
+ GLsizeiptr attrib_buff_sz = ((points_n * (3+2) * sizeof(GLfloat)) +
+ (points_n * 3 * sizeof(GLubyte)));
+
+ if ((attrib_buff_sz % sizeof(gltpoint_t)) != 0)
+ {
+ fprintf(stderr, "%s: fatal, gltpoint_t appears to be padded!\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* I call point a "vbo slice" */
+ size_t slices_n = attrib_buff_sz / sizeof(gltpoint_t);
+
+ gltpoint_t *gltpoints_arr = (gltpoint_t *) malloc(attrib_buff_sz);
+ if (!gltpoints_arr)
+ {
+ fprintf(stderr, "%s failed, %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+ perror("malloc");
+ return -1;
+ }
+
+ /* build interleaved data structure, seems cache friendly */
+ int i;
+ for (i = 0; i < slices_n; i++)
+ {
+ gltpoints_arr[i].normal[0] = norm_arr[i * 3 + 0];
+ gltpoints_arr[i].normal[1] = norm_arr[i * 3 + 1];
+ gltpoints_arr[i].normal[2] = norm_arr[i * 3 + 2];
+ gltpoints_arr[i].texcoord[0] = texcoord_arr[i * 2 + 0];
+ gltpoints_arr[i].texcoord[1] = texcoord_arr[i * 2 + 1];
+ gltpoints_arr[i].color[0] = color_arr[i * 3 + 0];
+ gltpoints_arr[i].color[1] = color_arr[i * 3 + 1];
+ gltpoints_arr[i].color[2] = color_arr[i * 3 + 2];
+ }
+
+ glGenBuffers(3, bufferobjects);
+
+ /* vertex data */
+ glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[0]);
+ glBufferData(GL_ARRAY_BUFFER, points_n * 3 * sizeof(float),
+ (const GLvoid *) vert_arr, GL_STATIC_DRAW);
+
+ /* attribute data, normals, texcoords, and color */
+ glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[1]);
+ glBufferData(GL_ARRAY_BUFFER, attrib_buff_sz,
+ (const GLvoid *) gltpoints_arr, GL_STATIC_DRAW);
+
+ /* indices data */
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobjects[2]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * indices_n,
+ (const GLvoid *) indices_arr, GL_STATIC_DRAW);
+
+ free(gltpoints_arr);
+
+ return 0;
+}
+
+static int gltDrawVBOInterleaved(GLuint *bufferobjects, size_t indices_n, GLenum mode)
+{
+ if (!bufferobjects || !indices_n)
+ return -1;
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ /* vertex data */
+ glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[0]);
+ glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
+
+ /* attribute data, normals, texcoords, and color */
+ glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[1]);
+ glNormalPointer(GL_FLOAT, sizeof(gltpoint_t), BUFFER_OFFSET(0));
+ glClientActiveTexture(GL_TEXTURE0);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(gltpoint_t), BUFFER_OFFSET(sizeof(GLfloat) * 3));
+ glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(gltpoint_t), BUFFER_OFFSET(sizeof(GLfloat) * 5));
+
+ /* indices data */
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobjects[2]);
+ glDrawElements(mode, indices_n, GL_UNSIGNED_SHORT, 0);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ return 0;
+}
+
+static void gl_error_check(const char *func, const char *file, const int line)
+{
+ GLenum err_code;
+ const GLubyte *err_str;
+
+ /* this single poke pops of the error from opengl state, hence the do loop */
+ if ((err_code = glGetError()) != GL_NO_ERROR)
+ {
+ fprintf(stderr, "errors encountered leading up to: %s in %s:%d\n",
+ func, file, line);
+
+ do
+ {
+ err_str = gluErrorString(err_code);
+ fprintf(stderr, "OpenGL error: %s\n", err_str);
+ }
+ while ((err_code = glGetError()) != GL_NO_ERROR);
+ }
+}
+
+static void resize(int w, int h)
+{
+ printf("window: resizing to %dx%d\n", w, h);
+ GLfloat fAspect = (GLfloat) w / (GLfloat) h;
+ if (h == 0)
+ h = 1;
+ glViewport(0, 0, w, h);
+
+ /* reset coordinate system */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ /* produce the perspective projection */
+ /* void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) */
+ gluPerspective(40.0f, fAspect, 1.0, 40.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ /* this needs to be ran again, glut does it for you I suppose */
+ SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_RESIZABLE);
+}
+
+static void setup_opengl(void)
+{
+ /* setup fog */
+ glEnable(GL_FOG);
+ glFogfv(GL_FOG_COLOR, fLowLight); /* set fog color to match background */
+ glFogf(GL_FOG_START, 4.0f);
+ glFogf(GL_FOG_END, 20.0f);
+ glFogi(GL_FOG_MODE, GL_LINEAR); /* fog equation */
+
+ glEnable(GL_DEPTH_TEST); /* hidden surface removal, aka Z-buffer */
+ glFrontFace(GL_CCW); /* counter clock-wise polygons face out */
+ glEnable(GL_CULL_FACE); /* do not calculate inside of a pyramid */
+
+ /* enable lighting, primitives now need to define color properties */
+ glEnable(GL_LIGHTING);
+
+ /* global illumination, ambient RGBA intensity of the entire scene */
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fLowLight);
+
+ /* setup and enable light 0 */
+ glLightfv(GL_LIGHT0, GL_AMBIENT, fMedLight);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, fShinyLight);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
+ glEnable(GL_LIGHT0);
+
+ /* set material properties to follow all glColor values */
+ /* all primitives specified after the glMaterial call are affected by the
+ * last values set, until another call to glMaterial is made */
+ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+
+ /* enable color tracking, should be called after glColorMaterial */
+ glEnable(GL_COLOR_MATERIAL);
+
+ /* set globally, sets specular reflection to a white color,
+ * this call follows all subsequent primitives */
+ glMaterialfv(GL_FRONT, GL_SPECULAR, fBrightLight);
+
+ /* default (0), by increasing this value you reduce the size and increase
+ * the focus of the specular highlight, causing a shiny spot to appear */
+ glMateriali(GL_FRONT, GL_SHININESS, 64);
+
+ /* multisampling for polygons, conflicts with *polygon* anti-aliasing */
+ /* enabled by default, that's what man page says, hmmm! */
+ glEnable(GL_MULTISAMPLE);
+
+ /* AA is disabled, but we will keep the blending function and hints though */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+
+ /* anisotropic filtering */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
+
+ /* how OpenGL combines the colors from texels with the color of the underlying
+ * geometry is controlled by the texture environment mode */
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ /* once texture is loaded and enabled, it will applied to every primitive
+ * that specifies coordinates, ORLY? */
+ glEnable(GL_TEXTURE_2D);
+
+ /* specular highlights for textured items */
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+ /* gray background */
+ glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+}
+
+static void keys(SDL_keysym *keysym, unsigned int *keys_held)
+{
+ switch (keysym->sym)
+ {
+ case SDLK_ESCAPE:
+ program_running = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+/* process SDL events */
+static void process_events(void)
+{
+ SDL_Event event;
+ unsigned static int keys_held[323];
+ SDLKey sym;
+
+ while (SDL_PollEvent(&event))
+ {
+ sym = event.key.keysym.sym;
+
+ switch (event.type)
+ {
+ case SDL_KEYUP:
+ {
+ /* reset the key to 0 */
+ keys_held[sym] = 0;
+ break;
+ }
+ case SDL_KEYDOWN:
+ {
+ keys_held[sym] = 1;
+ keys(&event.key.keysym, keys_held);
+ break;
+ }
+ case SDL_VIDEORESIZE:
+ {
+ resize(event.resize.w, event.resize.h);
+ break;
+ }
+ case SDL_QUIT:
+ {
+ program_running = 0;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+static void setup_sdl(void)
+{
+ if (SDL_Init(SDL_INIT_VIDEO) < 0 )
+ {
+ fprintf(stderr, "SDL: unable to init, %s\n", SDL_GetError());
+ exit(-1);
+ }
+ atexit(SDL_Quit);
+ SDL_WM_SetCaption("Programmable Pipeline", NULL);
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+
+ if ((screen = SDL_SetVideoMode(320, 240, 32, SDL_OPENGL | SDL_RESIZABLE)) == NULL)
+ {
+ fprintf(stderr, "SDL: unable to set video mode: %s\n", SDL_GetError());
+ exit(-1);
+ }
+
+ SDL_EnableUNICODE(1);
+ /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this
+ * for OpenGL, we do this ourselves */
+ SDL_Event resizeEvent;
+ resizeEvent.type = SDL_VIDEORESIZE;
+ resizeEvent.resize.w = 320;
+ resizeEvent.resize.h = 240;
+ SDL_PushEvent(&resizeEvent);
+}
+
+static void setup_glew(void)
+{
+ /* initalize glew */
+ GLenum glewerr = glewInit();
+ if (GLEW_OK != glewerr)
+ {
+ fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(glewerr));
+ exit(-1);
+ }
+ else
+ fprintf(stdout, "GLEW: using version %s\n", glewGetString(GLEW_VERSION));
+
+ /* display OpenGL version */
+ GLint major;
+ GLint minor;
+ glGetIntegerv(GL_MAJOR_VERSION, &major);
+ glGetIntegerv(GL_MINOR_VERSION, &minor);
+ fprintf(stdout, "GLEW: initialized OpenGL %d.%d\n", major, minor);
+}
+
+static int fragprog_create(GLuint *handle, const char *frag_src)
+{
+ if (!handle)
+ return -1;
+
+ GLint ret, length;
+ GLuint fragment;
+
+ /* create handle */
+ fragment = glCreateShader(GL_FRAGMENT_SHADER);
+
+ /* specify shader text */
+ glShaderSource(fragment, 1, &frag_src, NULL);
+
+ /* compile shader and check for any errors */
+ glCompileShader(fragment);
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &ret);
+ if (!ret)
+ {
+ glGetShaderiv(fragment, GL_INFO_LOG_LENGTH, &length);
+ GLchar info_log[length];
+ glGetShaderInfoLog(fragment, length, NULL, info_log);
+ fprintf(stderr, "%s", info_log);
+ glDeleteShader(fragment);
+ return -1;
+ }
+
+ /* save the handle */
+ *handle = fragment;
+
+ return 0;
+}
+
+static int vertprog_create(GLuint *handle, const char *vert_src)
+{
+ if (!handle)
+ return -1;
+
+ GLint ret, length;
+ GLuint vertex;
+
+ /* create handle */
+ vertex = glCreateShader(GL_VERTEX_SHADER);
+
+ /* specify shader text */
+ glShaderSource(vertex, 1, &vert_src, NULL);
+
+ /* compile shader and check for any errors */
+ glCompileShader(vertex);
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &ret);
+ if (!ret)
+ {
+ glGetShaderiv(vertex, GL_INFO_LOG_LENGTH, &length);
+ GLchar info_log[length];
+ glGetShaderInfoLog(vertex, length, NULL, info_log);
+ fprintf(stderr, "%s", info_log);
+ glDeleteShader(vertex);
+ return -1;
+ }
+
+ /* save the handle */
+ *handle = vertex;
+
+ return 0;
+}
+
+static int prog_create(GLuint *prog_handle, GLuint *vert_handle, GLuint *frag_handle)
+{
+ if (!prog_handle || !vert_handle || !frag_handle)
+ return -1;
+
+ GLint ret, length;
+ GLuint program;
+
+ /* create handle */
+ program = glCreateProgram();
+
+ /* attach shaders */
+ glAttachShader(program, *vert_handle);
+ glAttachShader(program, *frag_handle);
+
+ /* link, should be done whenever we attach or detach shaders to program */
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ret);
+ if (!ret)
+ {
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
+ GLchar info_log[length];
+ glGetProgramInfoLog(program, length, NULL, info_log);
+ fprintf(stderr, "%s", info_log);
+ glDeleteProgram(program);
+ return -1;
+ }
+
+ /* validate the program, should be done whenever program is linked or relinked */
+ glValidateProgram(program);
+ glGetProgramiv(program, GL_VALIDATE_STATUS, &ret);
+ if (!ret)
+ {
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
+ GLchar info_log[length];
+ glGetProgramInfoLog(program, length, NULL, info_log);
+ fprintf(stderr, "%s", info_log);
+ glDeleteProgram(program);
+ return -1;
+ }
+
+ /* save the handle */
+ *prog_handle = program;
+
+ return 0;
+}
+
+static void render(void)
+{
+ /* clear the window with current clearing color */
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* save the matrix state */
+ glPushMatrix();
+ {
+ /* draw ground using immiediate mode */
+ glDisable(GL_MULTISAMPLE);
+ glEnable(GL_BLEND);
+ glEnable(GL_LINE_SMOOTH);
+
+ GLfloat fExtent = 20.0f;
+ GLfloat fStep = 0.5f;
+ GLfloat y = -0.4f;
+ GLfloat iLine;
+
+ glLineWidth(1.0f);
+ glBegin(GL_LINES);
+ for (iLine = -fExtent; iLine <= fExtent; iLine += fStep)
+ {
+ glVertex3f(iLine, y, fExtent);
+ glVertex3f(iLine, y, -fExtent);
+ glVertex3f(fExtent, y, iLine);
+ glVertex3f(-fExtent, y, iLine);
+ }
+ glEnd();
+
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+ glEnable(GL_MULTISAMPLE);
+ /* end of ground */
+
+ glPushMatrix();
+ /* draw vbo */
+ glTranslatef(0.0f, 0.0f, -4.0f);
+ gltDrawVBOInterleaved(buffer_objects, 3, GL_TRIANGLES);
+ glPopMatrix();
+ }
+ /* restore the matrix state */
+ glPopMatrix();
+
+ /* buffer swap */
+ SDL_GL_SwapBuffers();
+}
+
+static void setup_vbo(void)
+{
+ /* setup a vbo triangle */
+ float vert_arr[9] = {
+ 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 0.5f, 0.83f, 0.0f };
+
+ float norm_arr[9] = {
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f };
+
+ float texcoord_arr[6] = {
+ 0.0f, 0.0f,
+ 1.0f, 0.0f,
+ 0.5f, 1.0f };
+
+ unsigned char color_arr[9] = {
+ 255, 0, 0,
+ 0, 255, 0,
+ 0, 0, 255 };
+
+ unsigned short indices_arr[3] = { 0, 1, 2 };
+
+ gltGenVBOInterleaved(buffer_objects, vert_arr, texcoord_arr, norm_arr,
+ color_arr, indices_arr, 3, 3);
+ gl_error_check(__FUNCTION__, __FILE__, __LINE__);
+}
+
+static void setup_shaders(void)
+{
+#if 0
+ char *vert_src, *frag_src;
+ loadfile_to_mem("vert", &vert_src);
+ loadfile_to_mem("frag", &frag_src);
+ free(vert_src);
+ free(frag_src);
+#endif
+
+ vertprog_create(&p.vert, vshader);
+ fragprog_create(&p.frag, fshader);
+ prog_create(&p.prog, &p.vert, &p.frag);
+
+ /* this is where the magic happens, fixed-functionality is replaced depending
+ * on what shaders are attached to the program */
+ glUseProgram(p.prog);
+
+ /* find out where the flicker constant lives, program has to be in use */
+ GLint flickerLocation = glGetUniformLocation(p.prog, "flickerFactor");
+ /* initially set the blink parameter to 1 (no flicker) */
+ if (flickerLocation != -1)
+ glUniform1f(flickerLocation, 1.0f);
+}
+
+static void dump_shaders(void)
+{
+ FILE *f1, *f2;
+ f1 = fopen("vert", "w");
+ f2 = fopen("frag", "w");
+
+ if (f1 && f2)
+ {
+ fwrite(vshader, sizeof(char), sizeof(vshader), f1);
+ fwrite(fshader, sizeof(char), sizeof(fshader), f2);
+
+ fclose(f1);
+ fclose(f2);
+ }
+ else
+ fprintf(stderr, "%s: failed\n", __FUNCTION__);
+}
+
+int main(int argc, char **argv)
+{
+ setup_sdl();
+ setup_glew();
+ setup_opengl();
+ /* would also check for vert and frag extensions, otherwise use fixed-func */
+ setup_vbo();
+ setup_shaders();
+ gl_error_check(__FUNCTION__, __FILE__, __LINE__);
+
+ /* main loop */
+ while (program_running)
+ {
+ process_events();
+ render();
+ }
+ gl_error_check(__FUNCTION__, __FILE__, __LINE__);
+
+ /* cleanup */
+ glDeleteProgram(p.prog); /* automatically detaches any shaders */
+ glDeleteShader(p.vert);
+ glDeleteShader(p.frag);
+ glDeleteBuffers(3, buffer_objects);
+ if (screen)
+ SDL_FreeSurface(screen);
+
+ puts("bye!");
+
+ return 0;
+}
+