Make the shaders work on NVidia
[gltest.git] / glutil_gl2.cpp
index ad89138d14f3748e90a52fd8919c3a4372b9794f..87d8e0cb33c2ec7f8153985e3bc08bf4cc5f3284 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "glutil.h"
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <string>
+#include <sstream>
 
-#include "glutil.h"
+// extension functions we use
+typedef GLuint (*GLCREATESHADERPROC) (GLenum type);
+typedef void (*GLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (*GLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (*GLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length);
+typedef void (*GLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (*GLCREATEPROGRAMPROC) (void);
+typedef void (*GLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (*GLLINKPROGRAMPROC) (GLuint program);
+typedef GLint (*GLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (*GLUSEPROGRAMPROC) (GLuint program);
+
+typedef void (*GLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (*GLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (*GLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef void (*GLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (*GLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+typedef void (*GLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+
+#ifdef CON_GL3
+// VAOs are only supported in GL3+, and not needed in earler contexts
+typedef void (*GLBINDVERTEXARRAYPROC) (GLuint array);
+typedef void (*GLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
+typedef void (*GLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+#endif
+
+GLGETSHADERIVPROC p_glGetShaderiv = NULL;
+GLGETSHADERINFOLOGPROC p_glGetShaderInfoLog = NULL;
+GLCREATESHADERPROC p_glCreateShader = NULL;
+GLSHADERSOURCEPROC p_glShaderSource = NULL;
+GLCOMPILESHADERPROC p_glCompileShader = NULL;
+GLCREATEPROGRAMPROC p_glCreateProgram = NULL;
+GLATTACHSHADERPROC p_glAttachShader = NULL;
+GLLINKPROGRAMPROC p_glLinkProgram = NULL;
+GLGETATTRIBLOCATIONPROC p_glGetAttribLocation = NULL;
+GLUSEPROGRAMPROC p_glUseProgram = NULL;
+
+GLVERTEXATTRIBPOINTERPROC p_glVertexAttribPointer = NULL;
+GLENABLEVERTEXATTRIBARRAYPROC p_glEnableVertexAttribArray = NULL;
+GLGENBUFFERSPROC p_glGenBuffers = NULL;
+GLBINDBUFFERPROC p_glBindBuffer = NULL;
+GLBUFFERDATAPROC p_glBufferData = NULL;
+GLDELETEBUFFERSPROC p_glDeleteBuffers = NULL;
+
+#ifdef CON_GL3
+GLBINDVERTEXARRAYPROC p_glBindVertexArray = NULL;
+GLDELETEVERTEXARRAYSPROC p_glDeleteVertexArrays = NULL;
+GLGENVERTEXARRAYSPROC p_glGenVertexArrays = NULL;
+#endif
+
+// resolve function pointers
+static T_proc resolveFunctionPointer(T_glGetProcAddress p_glGetProcAddress, const char *name)
+{
+       T_proc proc = p_glGetProcAddress(name);
+       if (proc == NULL) {
+               die("Error resolvung function %s\n", name);
+       }
+       return proc;
+}
+
+void resolveFunctionPointers(T_glGetProcAddress p_glGetProcAddress)
+{
+#ifdef CON_GL1
+       // we need to check if we have GL 2.0 or greater
+       std::string version = (char*)glGetString(GL_VERSION);
+       std::stringstream ssv(version);
+       std::string major;
+       std::getline(ssv, major, '.');
+       std::stringstream ssm(major);
+       int majorVersion;
+       ssm >> majorVersion;
+       if (majorVersion < 2) {
+               die("Need at least GL 2.0 to function properly, but detected version %d\n", majorVersion);
+       }
+#endif
+       
+       // now get the function pointers
+       p_glGetShaderiv = (GLGETSHADERIVPROC)resolveFunctionPointer(p_glGetProcAddress, "glGetShaderiv");
+       p_glGetShaderInfoLog = (GLGETSHADERINFOLOGPROC)resolveFunctionPointer(p_glGetProcAddress, "glGetShaderInfoLog");
+       p_glCreateShader = (GLCREATESHADERPROC)resolveFunctionPointer(p_glGetProcAddress, "glCreateShader");
+       p_glShaderSource = (GLSHADERSOURCEPROC)resolveFunctionPointer(p_glGetProcAddress, "glShaderSource");
+       p_glCompileShader = (GLCOMPILESHADERPROC)resolveFunctionPointer(p_glGetProcAddress, "glCompileShader");
+       p_glCreateProgram = (GLCREATEPROGRAMPROC)resolveFunctionPointer(p_glGetProcAddress, "glCreateProgram");
+       p_glAttachShader = (GLATTACHSHADERPROC)resolveFunctionPointer(p_glGetProcAddress, "glAttachShader");
+       p_glLinkProgram = (GLLINKPROGRAMPROC)resolveFunctionPointer(p_glGetProcAddress, "glLinkProgram");
+       p_glGetAttribLocation = (GLGETATTRIBLOCATIONPROC)resolveFunctionPointer(p_glGetProcAddress, "glGetAttribLocation");
 
-#if defined(CON_GL1)
-#error "GL1 contexts do not support GL2 functionality"
+#ifdef CON_GL3
+       p_glBindVertexArray = (GLBINDVERTEXARRAYPROC)resolveFunctionPointer(p_glGetProcAddress, "glBindVertexArray");
+       p_glDeleteVertexArrays = (GLDELETEVERTEXARRAYSPROC)resolveFunctionPointer(p_glGetProcAddress, "glDeleteVertexArrays");
+       p_glGenVertexArrays = (GLGENVERTEXARRAYSPROC)resolveFunctionPointer(p_glGetProcAddress, "glGenVertexArrays");
 #endif
 
+       p_glUseProgram = (GLUSEPROGRAMPROC)resolveFunctionPointer(p_glGetProcAddress, "glUseProgram");
+       p_glVertexAttribPointer = (GLVERTEXATTRIBPOINTERPROC)resolveFunctionPointer(p_glGetProcAddress, "glVertexAttribPointer");
+       p_glEnableVertexAttribArray = (GLENABLEVERTEXATTRIBARRAYPROC)resolveFunctionPointer(p_glGetProcAddress, "glEnableVertexAttribArray");
+       p_glGenBuffers = (GLGENBUFFERSPROC)resolveFunctionPointer(p_glGetProcAddress, "glGenBuffers");
+       p_glBindBuffer = (GLBINDBUFFERPROC)resolveFunctionPointer(p_glGetProcAddress, "glBindBuffer");
+       p_glBufferData = (GLBUFFERDATAPROC)resolveFunctionPointer(p_glGetProcAddress, "glBufferData");
+       p_glDeleteBuffers = (GLDELETEBUFFERSPROC)resolveFunctionPointer(p_glGetProcAddress, "glDeleteBuffers");
+}
+
 // shaders
 static const char *vertex_shader_source =
 "#version 100 \n\
+precision mediump float;\n\
+precision mediump int;\n\
 attribute vec2 position; \n\
 attribute vec3 color; \n\
 varying vec3 frag_color; \n\
@@ -38,6 +140,8 @@ void main() \n\
 }";
 static const char *fragment_shader_source =
 "#version 100 \n\
+precision mediump float;\n\
+precision mediump int;\n\
 varying vec3 frag_color; \n\
 void main(void) \n\
 { \n\
@@ -56,34 +160,36 @@ static struct {
 static void show_info_log(GLuint object)
 {
        GLint log_length;
-       glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
+       p_glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
        char *log = new char[log_length];
-       glGetShaderInfoLog(object, log_length, NULL, log);
+       p_glGetShaderInfoLog(object, log_length, NULL, log);
        fprintf(stderr, "%s", log);
        delete[] log;
 }
 
 static GLuint compile_shader(GLenum shader_type, const char *source)
 {
-       GLuint shader = glCreateShader(shader_type);
-       glShaderSource(shader, 1, &source, NULL);
-       glCompileShader(shader);
+       GLuint shader = p_glCreateShader(shader_type);
+       p_glShaderSource(shader, 1, &source, NULL);
+       p_glCompileShader(shader);
        GLint shader_ok;
-       glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
+       p_glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
        if (!shader_ok) {
                fprintf(stderr, "Failed to compile shader\n");
                show_info_log(shader);
                exit(1);
        }
+       checkGlError("Compiling shader");
        return shader;
 }
 
 static GLuint createArrayBuffer(GLsizeiptr size, GLfloat *data)
 {
        GLuint buffer;
-       glGenBuffers(1, &buffer);
-       glBindBuffer(GL_ARRAY_BUFFER, buffer);
-       glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+       p_glGenBuffers(1, &buffer);
+       p_glBindBuffer(GL_ARRAY_BUFFER, buffer);
+       p_glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+       checkGlError("Creating array buffer");
        return buffer;
 }
 
@@ -92,18 +198,27 @@ void initialise2dProjection()
 {
        GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_source);
        GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_source);
-       program = glCreateProgram();
-       glAttachShader(program, vertex_shader);
-       glAttachShader(program, fragment_shader);
-       glLinkProgram(program);
-       attributes.position = glGetAttribLocation(program, "position");
-       attributes.color = glGetAttribLocation(program, "color");
+       program = p_glCreateProgram();
+       p_glAttachShader(program, vertex_shader);
+       p_glAttachShader(program, fragment_shader);
+       p_glLinkProgram(program);
+       attributes.position = p_glGetAttribLocation(program, "position");
+       attributes.color = p_glGetAttribLocation(program, "color");
 }
 
 // draw a quad
 void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
 {
-       glUseProgram(program);
+       p_glUseProgram(program);
+       checkGlError("Enabling the shaders");
+
+#ifdef CON_GL3
+       // create a vertex array obect and use it
+       GLuint vao;
+       p_glGenVertexArrays(1, &vao);
+       p_glBindVertexArray(vao);
+       checkGlError("Creating a VAO");
+#endif
        
        // send vertex data to card with given attribute
        GLfloat vertex_buffer_data[] = {
@@ -113,7 +228,7 @@ void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1,
                x1, y2,
        };
        GLuint vertex_buffer = createArrayBuffer(sizeof(vertex_buffer_data), vertex_buffer_data);
-       glVertexAttribPointer(
+       p_glVertexAttribPointer(
                attributes.position,              /* attribute */
                2,                                /* size */
                GL_FLOAT,                         /* type */
@@ -121,7 +236,9 @@ void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1,
                0,                                /* stride */
                (void*)0                          /* array buffer offset */
        );
-       glEnableVertexAttribArray(attributes.position);
+       checkGlError("Preparing vertex data");
+       p_glEnableVertexAttribArray(attributes.position);
+       checkGlError("Sending vertex data");
        
        // same with color data
        GLfloat color_buffer_data[] = {
@@ -131,7 +248,7 @@ void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1,
                red, green, blue,
        };
        GLuint color_buffer = createArrayBuffer(sizeof(color_buffer_data), color_buffer_data);
-       glVertexAttribPointer(
+       p_glVertexAttribPointer(
                attributes.color,              /* attribute */
                3,                             /* size */
                GL_FLOAT,                      /* type */
@@ -139,12 +256,19 @@ void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1,
                0,                             /* stride */
                (void*)0                       /* array buffer offset */
        );
-       glEnableVertexAttribArray(attributes.color);
+       checkGlError("Preparing color data");
+       p_glEnableVertexAttribArray(attributes.color);
+       checkGlError("Sending color data");
        
        // draw
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+       checkGlError("Drawing");
        
        // cleanup
-       glDeleteBuffers(1, &vertex_buffer);
-       glDeleteBuffers(1, &color_buffer);
+       p_glDeleteBuffers(1, &vertex_buffer);
+       p_glDeleteBuffers(1, &color_buffer);
+#ifdef CON_GL3
+       p_glDeleteVertexArrays(1, &vao);
+#endif
+       checkGlError("Doing cleanup");
 }