#define GL_GLEXT_PROTOTYPES 1

#include <GL/glut.h> // this includes <GL/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Like the previous examples this program only clears the window to a
// color. This program adds to the previous examples the infrastructure 
// necessary to compile, link and use a vertex and fragment shader pair.
// OpenGL 3.2 core requires that a vertex and fragment shader be defined 
// in order to draw. While this may seem like a lot of code, it is largely 
// boiler plate stuff. 
//
// Whiile reading this code it is important to bear in mind that this
// code has many shortcomings that would be unacceptable in a real application.
// Some of these shortcomings will be corrected in later examples. 
// Also bear in mind that with this example and the one that follows we're
// trying to get an image to work with on the screen as quickly as possible
// and then build more rigorous explanations from a base of code which can be
// used for experimentation. I encourage you take these programs and
// change them to see what affect your changes have.

// The typical pattern for an OpenGL application is:
// 1. setup OpenGL structures (textures, vertex buffers, shaders)
// 2. draw 
// Generally speaking, step 1 happens far less often than step 2, at least for
// large structures or large updates. The c struct below, called State, will be
// used to store handles to the structures OpenGL is asked to create. Drawing
// is accomplished by using the handles in OpenGL calls.  Demonstrated in this
// program is shader creation, and shader use. Though since we don't have any
// geometry to drawn, we cannot yet see the affect shader program would have.
//
// Below is space for one handle, for a shader program, in the State structure.
struct State {
    GLhandleARB shaderProgram;
};
State state;

// How are Shaders used in OpenGL?
//
// Consider a simple case. Suppose we have two vertices in 3D space,
// defining a line in 3D space, to be drawn on the 2D screen. 
//
// It can be shown that, if we can find the pixel on the screen where each
// vertex should be drawn, then all the rest of the pixels that connect the two
// vertices (to make up the line) can be drawn in 2D, as though we were
// connecting the two dots on a piece of paper. This is much less computationally
// costly than having to transform each individual point on the line.
//
// So, ideally, we can separate the job of finding the pixel where each of the
// two vertices of the line land on the screen from the job of filling in the
// line on the screen. This is a dramatically oversimplified explanation, but
// it can serve as an initial working model of what the vertex shader and the
// fragment shader do. We will refine this model later. 
//
// Here's a small refinement now:
// - For each vertex in the line, the vertex shader is called upon to find 
//   where that vertex should land on the screen.   
// - For each pixel on the line, the fragment shader is called upon to draw 
//   that pixel on the screen.
//
// Notice that the fragment shader doesn't determine *whether* a pixel is on
// the line or not. Some other piece of code figures that out before the
// fragment shader is invoked.
//
// Note that other kinds of shaders exist. Note also the use of the word
// 'fragment' rather than 'pixel'. Think of a fragment as a pixel with
// some extra data associated with it. Right now think of a fragment as
//
// struct fragment {
//  int x,y;
//  float r,g,b,a;
//  ...
// }; 
// That is, a fragment has, at least, an x,y position on the screen, and a color.
//
// The programmer's model of OpenGL is a pipeline. The simplified pipeline
// presented so far is this:
//
//                     vertices
//                        |
//                        |
//                  vertex shader
//                        |
//                        |
//               magic which converts
//                  vertices into
//                    fragments
//                        |
//                        |
//                 fragment shader
//                        |
//                        |
//                  output image on
//                    the screen
//
//
// The machinery to set shaders up is analogous to compiling a c source code program: 
// 1. create a shader program 
// 2. attach objects to the program (at least one object for the vertex shader, and one for the fragment shader)
// 3. link the objects together
// 4. run the program
//
// Below is the source for a vertex shader. Note that is a plain
// old C array of type GLchar (think, just a char). Each line
// ends with '\n' a new line to make error prints easier to read
// followed by '\', the line continuation character. Real code 
// might load this as a text file at startup.
// The OpenGL shading language (GLSL) is a c like language with
// some restrictions and some extensions.
//
// Line by line:
//
// #version 150        // tell the shader complier we want version 1.50 of GLSL
//                     // this is analogous to a preprocessor directive.
//   
//
//                      //  'in' declares this variable to be a vertex shader input.
//                      //       That is, for what ever follow 'in',  
//                      //       there is one of these things per vertex.
// in vec3 vertex;      //  'vec3' declares this variable to be a floating point 3 vector.
//                      //  'vertex' is the name of the variable. So its members can be
//                      //           accessed with vertex.x, vertex.y, vertex.z,
//                      //           or vertex[0], vertex[1], vertex[2]
// 
//
// 
// void      // main never has a return value.
//
// main()    // just as in c/c++ main is where execution of the shader
//           // begins. And, just like c/c++ you may have function calls
//           // and even functions complied as separate objects. There
//           // must be exactly one 'main()' per shader type (1 main in
//           // the vertex shader, 1 main the fragment shader).
//           // 'main()' never has arguments.
//
//
//                                    // 'gl_Position' is a special variable for communicating with OpenGL's
//                                    //               fixed function pipeline. In the model above, the magic stage
//                                    //               of the pipeline. All variable names beginning with
// gl_Position = vec4(vertex,1.0);    //               'gl_' are reserved for OpenGL. A vertex shader writes
//                                    //               a vertex position to 'gl_Position'. 
//                                    // 'vec4()' This is a c++ style type constructor for a 4 component floating
//                                    //          point vector. 'vec4(vertex,1.0)' constructs the vec4 like this:
//                                    //          vec4(vertex.x, vertex.y, vertex.z, 1.0);
// 
// Here's the shader source
GLchar vertexShaderSource[] = "\n\
#version 150\n\
in vec3 vertex;\n\
void\n\
main()\n\
{\n\
    gl_Position = vec4(vertex,1.0);\n\
}\n\
";

// Below is the source for a fragment shader. Note the similarity
// to the vertex shader. We'll take a look at the differences from the shader above.
//
//                            // 'out' declares the variable to be a fragment shader output.
//                            //       As you might expect, a fragment shader principally outputs a color.
// out vec4 fragmentColor;    // Colors are represented as RGBA values. 
//                            //       R = red
//                            //       G = green
//                            //       B = blue
//                            //       A = alpha (the opacity of the fragment 1 = opaque, 0 = invisible)
//                            //       RGBA values are are clamped to [0,1]
//                            // 'vec4' This again is a floating point 4 component vector.
//                            // 'fragmentColor' This is the name of variable.
//                            // Writing a color to this variable will cause fragments to be drawn in that color. 
//                            // The first 'out vec4' variable declared will be the fragment color written to the window.
//                            // 
//
// out fragmentColor = vec4(0.0, 1.0, 0.0, 1.0); // This line writes the green to the fragmentColor. The fragments for all
//                                               // primitives will be green.
// 
// Here's the shader source
GLchar fragmentShaderSource[] = "\n\
#version 150\n\
out vec4 fragmentColor;\n\
void\n\
main()\n\
{\n\
    fragmentColor = vec4(0.0, 1.0, 0.0, 1.0);\n\
}\n\
";

// This function wraps up the code required to compile a shader.
// it returns a GL handle to the complied shader
// 'text' is the shader text
// 'type' is expected to be either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
// In most of the code examples that I write, I tend to leave out a lot of
// error checking code for the sake of clarity. The first exception to that rule
// is the glutReportErrors() at the end of each frame, which is helpful for debugging.
// The second exception is for shader compilation and linking. 
// Just as you wouldn't expect to write c source without looking at complier error
// output, you wouldn't do that during the shader development process either.
// Furthermore, if for some reason your shader doesn't compile or your shader program
// doesn't link, then OpenGL's fallback is to its fixed function pipeline. This means
// that errors may be difficult to understand. Another reason to catch them early. 
// So, in the code below I do extensive error checking.
GLhandleARB
shaderCompile(const GLchar *text, GLenum type)
{
    GLhandleARB shaderHandle;
    GLint       status;
    GLint       loglen;
    GLint       maxloglen;
    GLchar     *log = 0;

    // Create a shader handle.
    // This gives us a way of setting up a new shader.
   shaderHandle = glCreateShader(type);

   // Check for error and exit if we find one.
    if (shaderHandle == 0) {
        fprintf(stderr,"glCreateShader() failed.\n");
        fprintf(stderr,"Possibly outside an OpenGL context. Possible out of resources.\n");
        exit(1);
    }

    // Specify the source code for the shader. 
    // Shader text can be specified as either a single string of GLchars
    // or an array of character strings. Below I specify the shader source
    // as a single, NULL terminated array of strings
    glShaderSource(shaderHandle, 1, &text, NULL);
    // Check for errors and print them
    glutReportErrors();

    // Ask GL to compile the shader into object code
    glCompileShader(shaderHandle);
    // Check for errors and print them
    glutReportErrors();

    // Ask GL if this source compiled.
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);

    // If status is not 0, then the source code successfully 
    // complied into object code and we return the handle we originally 
    // created.
    if (status != 0) {
        return shaderHandle;
    }

    // otherwise we have a compilation error. 
    // So we get the error log, print the error log, and print out
    // the text of the offending shader. Then we exit. 

    // Get the error log length
    // log length includes the c string null terminator
    glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &maxloglen);
    log = new GLchar[maxloglen];

    // get the error log and store it in 'log'
    glGetShaderInfoLog(shaderHandle, maxloglen, &loglen, log);

    fprintf(stderr,"compile failed.\n");
    fprintf(stderr,"shader text:\n");
    fprintf(stderr,"------------\n");
    fprintf(stderr,"%s\n",text);
    fprintf(stderr,"log text:\n");
    fprintf(stderr,"------------\n");
    fprintf(stderr,"%s\n",log);

    delete [] log;
    exit(1);
}

// This function wraps up the code required to compile a shader program.
// it returns a GL handle to the complied shader program.
// 'vertex' is the shader source code text for the vertex shader
// 'fragment' is the shader source code text for the fragment shader.
// Again, we check errors everywhere we can to be sure we catch them
// early.
GLhandleARB
shaderProgramBuild(const GLchar *vertex, const GLchar *fragment)
{
    GLhandleARB programHandle;
    GLint       status;
    GLint       loglen;
    GLint       maxloglen;
    GLchar     *log = 0;

    // Create a shader program. This again is an empty handle which we
    // will fill in with data.
    programHandle = glCreateProgram();

    // Exit if there is an error.
    if (programHandle < 1) {
        fprintf(stderr,"glCreateShader() failed.\n");
        exit(1);
    }

    // Check for any other errors and print them.
    glutReportErrors();

    // Attach the vertex shader object to the program.
    glAttachShader(programHandle, shaderCompile(vertex,GL_VERTEX_SHADER));
    // Attach the vertex shader object to the program.
    glAttachShader(programHandle, shaderCompile(fragment,GL_FRAGMENT_SHADER));
    // Check for any other errors and print them.
    glutReportErrors();

    // Attempt to the link the shader objects into a program
    glLinkProgram(programHandle);
    // Check for any other errors and print them.
    glutReportErrors();

    // Ask GL if this source compiled.
    glGetProgramiv(programHandle, GL_LINK_STATUS, &status);

    // If status is not 0, then the objects successfully 
    // linked into shader program and we return the handle we originally 
    // created.
    if (status != 0) {
        return programHandle;
    }

    // otherwise we have a link error. 
    // So we get the error log and print the error log.
    // Then we exit. 

    // Get the info log length
    // log length includes the c string null terminator
    glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &maxloglen);
    log = new GLchar[maxloglen];

    // get the info log and store it in 'log'
    glGetProgramInfoLog(programHandle, maxloglen, &loglen, log);

    fprintf(stderr,"link failed.\n");
    fprintf(stderr,"log text:\n");
    fprintf(stderr,"------------\n");
    fprintf(stderr,"%s\n",log);

    delete [] log;
    exit(1);
}

// OpenGL calls will only work when there is an 'active' or 'bound'
// OpenGL context. Think of the OpenGL context as a struct full of
// variables that define the current OpenGL state. For instance,
// the size of the viewport, which we set with glViewport(), is
// part of the OpenGL context. All OpenGL calls must be made within
// an OpenGL context, and those calls usually affect just that OpenGL
// context. For instance each window in an application might correspond
// to an OpenGL context. If a context weren't bound, then call wouldn't know
// what context to affect. 
//
// Unless we explicitly bind the context, which is usually done with
// a call called 'makeCurrent' (or something similar), we cannot
// assume that we can make an OpenGL call and have it succeed. In
// some circumstances a GL call outside a bound context could crash 
// your program.
//
// Virtually all toolkits which support OpenGL will provide a 
// call equivalent to 'makeCurrent'. They will also usually
// guarantee that when the 'redraw', 'display', or 'paint' callback
// is run, that an OpenGL is bound. This is true for GLUT. 
// We know that when the 'display' function is called, our
// OpenGL context is bound and we can make GL calls.
//
// This initialize function is called once, from within display,
// so we know that our OpenGL calls will run in an OpenGL context.
void
initialize()
{
    // this function is where OpenGL initialization will occur.

    // changing the color to medium red just for fun
    // moved the setting of clear color to the central location of OpenGL initialization
    glClearColor(0.4f, 0.0f, 0.0f, 1.0f) ;

    // store the handle to the successfully complied and linked shader program so that we
    // can use it during drawing.
    state.shaderProgram = shaderProgramBuild(vertexShaderSource, fragmentShaderSource);
}

void
display()
{
    // added this static boolean do do one-time OpenGL related initialization.
    static bool doInitialize = true;

    if (doInitialize == true) {
        doInitialize = false;
        initialize();
    }


    glClear(GL_COLOR_BUFFER_BIT) ;

    // bind the shader program created in initialize()
    // Any draw calls made while this program is in use will
    // run through this shader program
    glUseProgram(state.shaderProgram);

    // Draw something here. We have nothing to draw yet! Next
    // example will finally draw something!

    // Tell OpenGL to unbind our shader program.
    glUseProgram(0);

    glFlush();

    glutReportErrors();
    return ;
}

void
keyboard(unsigned char key, int x, int y)
{
    switch (key) {
        // exit if the user hits the escape key or the 'q' key
        case 27:
        case 'q':
            exit(0);
            break;

        default:
            // print data to stderr so we know a key had been hit
            fprintf(stderr,"key %d hit. mouse at %d %d\n",key,x,y);
            break;
    };
}

void
mouse(int button, int state, int x, int y)
{
    switch (button) {

        case GLUT_LEFT_BUTTON:
            if (state == GLUT_DOWN) {
                fprintf(stderr,"left mouse button pressed\n");
            } else if (state == GLUT_UP) {
                fprintf(stderr,"left mouse button released\n");
            }
            break;

        case GLUT_MIDDLE_BUTTON:
            break;

        case GLUT_RIGHT_BUTTON:
            break;
    };
}

void
reshape(int width, int height)
{
    glViewport(0, 0, width, height);
}

int main(int argc, char **argv)
{
    glutInit( &argc, argv);
    glutInitWindowSize(800,600);
    glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);

    glutCreateWindow("example-02");

    glutDisplayFunc( display );
    glutKeyboardFunc( keyboard );
    glutMouseFunc( mouse );
    glutReshapeFunc( reshape );

    glutMainLoop() ;

    return(0) ;
}