OpenGL 3.0 model-view transformation

Hello ALL!!!
Please help in converting to opengl 3.0. Especially with regard to model-view transformation. Given that glPushMatrix, glPopMatrix, glTranslate, glRotate, glScale declared as “deprecated”. Please attach a small example of code.

You can use deprecated stuff in OpenGL 3.0 contexts. Why would you want to move to “pure” 3.x anyway? The only reason I see is adopting all-shader approach, but if you had that goal you wouldn’t be asking this questions in the first place.

Suppose you have a basic vertex shader with uniform variables you must control that accomplishes the same functionality as glPushMatrix, glTranslate, etc since 3.0 doesn’t do this for you anymore. The most basic shader would then be:

const GLchar g_vertexShader[] = {"#version 130
",
"uniform mat4 glm_ProjectionMatrix;
",
"uniform mat4 glm_ModelViewMatrix;
",
"in vec4 dgl_Vertex;
",
"void main(void)
",
"{
",
" gl_Position = glm_ProjectionMatrix
glm_ModelViewMatrix*dgl_Vertex;
",
"}
"
};

In essence, you now have to explicitly define your our matrices and vertex names (glm_ProjectionMatrix, glm_ModelViewMatrix, dgl_Vertex) to replace the deprecated ones of similar name that existed already.

Then in your code you must set a uniform 4x4 matrix for the
glm_ProjectionMatrix and glm_ModelViewMatrix explicitly with
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) );

But how do you set and manipulate these two matrices? I found a nice library called OpenGL Mathematics ( http://glm.g-truc.net/ ) that is a set of C++ headers that work nicely for me.

Basically all the openGL functions that you mention map nicely using this library.
I use the c++ STD library to get the push/pop functionality using the std::stack

#include <stack>

std::stack<mat4> glm_ProjectionMatrix;
std::stack<mat4> glm_ModelViewMatrix;

//glMatrixMode(GL_MODELVIEW); // unecessary since use matrix by name
glm_ModelViewMatrix.top() = mat4(1.0); // glLoadIdentity
glm_ModelViewMatrix.top() *= lookAt( vec3(eyeX, eyeY, eyeZ), vec3(centerX, centerY, centerZ), vec3(upX, upY, upZ)); //=gluLookAt()
glm_ModelViewMatrix.push(glm_ModelViewMatrix.top()); // = glPushMatrix();
glm_ModelViewMatrix.top() *=translate( vec3(0.0, 0.0, 0.25) ); //= glTranslate()
glm_ModelViewMatrix.top() *=rotate(45.0f, vec3(1.0, 1.0, 0.0) ); //=same as glRotate()
glm_ModelViewMatrix.top() *=scale( vec3(0.2, 0.2, 0.2) ); //=same as glScale()

glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) ); // set the shader value

Draw_vao(1);

glm_ModelViewMatrix.pop(); //= glPopMatrix()

and GLM even has all the lookat, perspective, ortho, frustrum gl commands too!

//glMatrixMode(GL_PROJECTION); // unecessary since use matrix by name
glm_ProjectionMatrix.top() = mat4(1.0); //glLoadIdentity
glm_ProjectionMatrix.top() *= perspective(20.0f,ratio,1.0f,3.0f); //=glPerspective
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) ); // set the shader value

This all seems complicated if your seeing shaders for the first time but in my opinion GLM has some great aspects for helping fill the “matrix” gap left by the 3.0 void. Note, the .top() is part of the c++ standard template library
and is used to get the topmost matrix on the stack.

I saw some good background reading material at http://www.songho.ca/opengl/gl_transform.html
explaining how openGL does the matrix transformations in the prior openGL 3.0 era.

Here is a complete code example that I have been using to learn what the consequences of opengl 3.0 might be. This uses glm, freeglut, and glew libraries. I am using g++ compiler … hope seeing the code helps explain a little better my previous post.

Once compiled and running change the camera view:
press t,T to rotate camera theta
press p,P to rotate camera phi


//on linux or mingw: g++ demo.cpp -lglut -lGLEW
// modified to use GLM library from http://pheatt.emporia.edu/courses/2005/cs410f05/hand14/hand14.htm
// modified to use camera at begining of MODELVIEW Transformations, not in the Projection Transform! see http://www.sjbaker.org/steve/omniv/projection_abuse.html
#include <GL/glew.h>     // great opengl extensions helper
#include <GL/freeglut.h> // use of opengl 3.0 context requires freeglut from svn!

#include <glm/glm.h> //OpenGL Mathematics (GLM).  A C++ mathematics library for 3D graphics.
#include <glm/glmext.h>
#include <glm/GLM_VIRTREV_address.h> // gives helper function address(X) instead of using &X[0][0]
namespace glm
{
          // read glm/gtx/transform.h for function prototypes
          using GLM_GTX_transform;
          using GLM_GTX_transform2; // for lookAt
          using GLM_GTX_matrix_projection;
}
using namespace glm;

#include <cstdio>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stack>
#include <cstring>
#include <cassert>

namespace global {
  int theta = 0;
  int   phi = 0;
  GLfloat ratio = 1.0;
  int width = 512;
  int height = 512;
};

class CustomGraphicsPipeline
{
			GLuint shader_id;
      std::stack<mat4> glm_ProjectionMatrix; //cpu-side
			GLint  glm_ProjectionMatrix_id; //cpu-side hook to shader uniform
      std::stack<mat4> glm_ModelViewMatrix; //cpu-side
			GLint  glm_ModelViewMatrix_id; //cpu-side hook to shader uniform
			GLuint vao_id[2]; // vertex array object hook id
			GLuint vao_elementcount[2]; // number of attribute elements in vao ie number of vertices
			GLuint vao_primitivetype[2]; // type [GL_LINE_LOOP|GL_TRIANGLES|etc] 
		public:
			CustomGraphicsPipeline() :
       shader_id(NULL),
       glm_ProjectionMatrix_id(NULL),
       glm_ModelViewMatrix_id(NULL)
      {
       glm_ProjectionMatrix.push( mat4(1.0f) ); // identity matrix
       glm_ModelViewMatrix.push( mat4(1.0f) ), // identity matrix
       vao_id[0]=NULL; 
       vao_id[1]=NULL;
       vao_elementcount[0]=0; 
       vao_elementcount[1]=0;
       vao_primitivetype[0] = GL_LINE_LOOP;
       vao_primitivetype[1] = GL_TRIANGLES;
      }
			~CustomGraphicsPipeline() {}

      bool Init()										// All Setup For OpenGL Goes Here
      {
        GLint ret = true; // optimistic return value upon completion of execution 

        std::cout << "GL_VERSION: " << glGetString(GL_VERSION) << std::endl;
        std::cout << "GL_EXTENSIONS: " << glGetString(GL_EXTENSIONS) << std::endl;
        std::cout << "GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
        std::cout << "GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
        std::cout << "GLU_VERSION: " << gluGetString(GLU_VERSION) << std::endl;
        std::cout << "GLU_EXTENSIONS: " << gluGetString(GLU_EXTENSIONS) << std::endl;
        std::cout << "GLUT_API_VERSION: " << GLUT_API_VERSION << std::endl;
#ifdef GLUT_XLIB_IMPLEMENTATION
        std::cout << "GLUT_XLIB_IMPLEMENTATION: " << GLUT_XLIB_IMPLEMENTATION << std::endl;
#endif
        std::cout << "press t,T to rotate camera theta" << std::endl;
        std::cout << "press p,P to rotate camera phi" << std::endl;

        glEnable(GL_DEPTH_TEST);
        glClearColor(0.2f, 0.2f, 0.2f, 0.5f);

      //Datas destioned for video memory, can be local (and lost after bound to GPU!). 
        GLfloat vertices0[] = { // dgl_Vertex
          1.0, -1.0, 0.0, 1.0, // xyzw 
         -1.0, -1.0, 0.0, 1.0,
          0.0,  1.0, 0.0, 1.0
        };
        size_t Nbytes_vertices0=sizeof(vertices0);

        GLfloat colors0[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors0=sizeof(colors0);

        GLfloat vertices1[] = { // dgl_Vertex
          0.5, -0.5, 0.0, 1.0, // xyzw 
         -0.5, -0.5, 0.0, 1.0,
          0.0,  0.5, 0.0, 1.0
        }; 
        size_t Nbytes_vertices1=sizeof(vertices1);

        GLfloat colors1[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors1=sizeof(colors1);

        const GLchar *g_vertexShader[] = {"#version 130
",
         "uniform mat4 glm_ProjectionMatrix;
", // replaces deprecated gl_ProjectionMatrix see http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
         "uniform mat4 glm_ModelViewMatrix;
", // replaces deprecated gl_ModelViewMatrix
         "in		 vec4 dgl_Vertex;
", // replaces deprecated gl_Vertex
         "in		 vec4 dgl_Color;
", // replaces deprecated gl_Color
         "invariant out	vec4 Color;
", // to fragment shader
         "void main(void)
",
         "{
",
         "	Color = dgl_Color;
",
         "	gl_Position = glm_ProjectionMatrix*glm_ModelViewMatrix*dgl_Vertex;
", // replaces deprecated ftransform() see http://www.songho.ca/opengl/gl_transform.html
         "}
"
        };

        const GLchar *g_fragmentShader[] = {"#version 130
",
         "invariant in vec4 Color;
", // from vertex shader
         "out  vec4 dgl_FragColor;
", // replaces deprecated gl_FragColor
         "void main(void)
",
         "{
",
         "  dgl_FragColor = Color;
", // gl_FragColor is deprecated
         "}
"
        };
  
      // compile Vertex shader
        GLuint m_vxShaderId = glCreateShader(GL_VERTEX_SHADER);
        GLsizei nlines_vx = sizeof(g_vertexShader)/sizeof(const GLchar*);
        glShaderSource(m_vxShaderId, nlines_vx, (const GLchar**)g_vertexShader, NULL);
        glCompileShader(m_vxShaderId);
        CheckShader(m_vxShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the vertex shader!");

      // compile Fragment shader
        GLuint m_fgShaderId = glCreateShader(GL_FRAGMENT_SHADER);
        GLsizei nlines_fg = sizeof(g_fragmentShader)/sizeof(const GLchar*);
        glShaderSource(m_fgShaderId, nlines_fg, (const GLchar**)g_fragmentShader, NULL);
        glCompileShader(m_fgShaderId);
        CheckShader(m_fgShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the fragment shader!");
	  
      // link shaders
        shader_id = glCreateProgram();
        glAttachShader(shader_id, m_vxShaderId);
        glAttachShader(shader_id, m_fgShaderId);
        glLinkProgram(shader_id);
        CheckShader(shader_id, GL_LINK_STATUS, &ret, "unable to link the program!");
 
      //hooks from CPU to GPU
        //define Uniform hooks
        glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, "glm_ProjectionMatrix");
        glm_ModelViewMatrix_id = glGetUniformLocation(shader_id, "glm_ModelViewMatrix");

        //guard that all attributes have same number of elements
        assert(Nbytes_vertices0/4/sizeof(GLfloat)==Nbytes_colors0/4/sizeof(GLfloat));
        vao_elementcount[0]=Nbytes_vertices0/4/sizeof(GLfloat); // number of elements for first VAO
        assert(Nbytes_vertices1/4/sizeof(GLfloat)==Nbytes_colors1/4/sizeof(GLfloat));
        vao_elementcount[1]=Nbytes_vertices1/4/sizeof(GLfloat); // number of elements for second VAO

        //create and define vertex array objects
        glGenVertexArrays(2, &vao_id[0]); // vao_id[#] will be referenced in Draw()
        defineVertexArrayObject(vao_id[0],Nbytes_vertices0,4,GL_FLOAT,vertices0,colors0); //VertexAttribArray: vertices0, colors0
        defineVertexArrayObject(vao_id[1],Nbytes_vertices1,4,GL_FLOAT,vertices1,colors1); //VertexAttribArray: vertices1, colors1

      // finally, use the shader for rendering 
        glUseProgram(shader_id);            // select the shaders program

        return ret;										// Initialization Went OK?
      }

      void defineVertexArrayObject(GLuint vaoId, size_t Nbytes, GLint size, GLenum type, GLfloat *vertices, GLfloat *colors)
      {
        //enable vertex array object to be defined
        glBindVertexArray(vaoId);

        //generate VBO foreach 'in'; dgl_Vertex and dgl_Color
        GLuint m_vboId[2];
        glGenBuffers(2, &m_vboId[0]);

        //"in		 vec4 dgl_Vertex;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[0] );	// enable the 1st VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes, vertices, GL_STATIC_DRAW); // fill the VBO with vertices data
        const GLuint index_mPosition = glGetAttribLocation(shader_id,"dgl_Vertex"); // get ID for "dgl_Vertex"
        glVertexAttribPointer(index_mPosition, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Vertex" attribute
        glEnableVertexAttribArray(index_mPosition);		// enable VBO vertex attribute ("dgl_Vertex")

        //"in		 vec4 dgl_Color;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[1]);	// enable the 2nd VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes , colors, GL_STATIC_DRAW); // fill the 2nd VBO with colors data
        const GLuint index_mcolor = glGetAttribLocation(shader_id,"dgl_Color"); // get ID for "dgl_Color"
        glVertexAttribPointer(index_mcolor, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Color" attribute
        glEnableVertexAttribArray(index_mcolor);		// enable VBO vertex attribute ("dgl_Color")
      }

      void CheckShader(GLuint id, GLuint type, GLint *ret, const char *onfail)
      {
       //Check if something is wrong with the shader
       switch(type) {
       case(GL_COMPILE_STATUS):
         glGetShaderiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetShaderInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
         break;
       case(GL_LINK_STATUS):
         glGetProgramiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetProgramInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
       default:
         break;
       };
      }

      void Draw_vao(size_t index)
      {
        glBindVertexArray(vao_id[index]);		// select the vertex array object:vao_id[index] by definiton using vertices_index,colors_index
        glDrawArrays(vao_primitivetype[index], 0, vao_elementcount[index]);	// draw the array (at the speed of light)
      }

      void Draw()									// Here's Where We Do All The Drawing
      {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) );	// set the rotation/translation/scale matrix 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        //glm_ModelViewMatrix.top() *= translate(       vec3(0.5, 0.5, 0.0) );
        glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(0.0, 0.0, 1.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );	// set the rotation/translation/scale matrix 

        Draw_vao(0);

        glm_ModelViewMatrix.pop();
        } 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        glm_ModelViewMatrix.top() *= translate(       vec3(0.0, 0.0, 0.25) );
        //glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(1.0, 1.0, 0.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );	// set the rotation/translation/scale matrix 

        Draw_vao(1);

        glm_ModelViewMatrix.pop();
        }
      }
      
      bool Reshape(GLfloat ratio)
      { 
          //glMatrixMode(GL_PROJECTION);
          glm_ProjectionMatrix.top() = mat4(1.0); //glLoadIdentity
          glm_ProjectionMatrix.top() *= perspective(20.0f,ratio,1.0f,3.0f);
      		//glLoadMatrixf(address(glm_ProjectionMatrix.top()));
          glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
      }

      bool SetCamera(GLfloat theta, GLfloat phi)
      { 
        ////////////// 
          // Set the camera view.
          static const double radianFactor = acos(0.0) / 90.0; 
      	  float r = 1.0f*2.0; // approx. want half way between near + far (see perspective)
      	  float eyeX = r * sin(theta * radianFactor) * cos(phi * radianFactor);
      	  float eyeY = r * sin(theta * radianFactor) * sin(phi * radianFactor);
      	  float eyeZ = r * cos(radianFactor * theta);

      	  float centerX = 0, centerY = 0, centerZ = 0;
      	  float upX = 0, upY = 1.0f, upZ = 0;

      	  //glMatrixMode(GL_MODELVIEW);
          glm_ModelViewMatrix.top() = mat4(1.0); // LoadIdentity
          glm_ModelViewMatrix.top() *= lookAt( vec3(eyeX, eyeY, eyeZ), vec3(centerX, centerY, centerZ), vec3(upX, upY, upZ)); 
      		//glLoadMatrixf(address(glm_ModelViewMatrix.top()));
          glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );

        return true; 
      }
};

// GLOBAL ///////////////////////////////////////////////////////////
CustomGraphicsPipeline Scene;
/////////////////////////////////////////////////////////////////////

static void timer(int dt_msec)
{
  static GLfloat time_msec = 0.0;
  time_msec += dt_msec; // absolute time

  Scene.SetCamera(global::theta, global::phi);

	glutPostRedisplay();
	glutTimerFunc(30,timer,30); // come back in 30msec
}

static void display(void) 
{
	Scene.Draw();
  glutSwapBuffers();
}

static void reshape(int w, int h) 
{
    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Prevent a divide by zero, when window is too short
    if(h == 0) h = 1;

    global::width = w;
    global::height = h;
    global::ratio = 1.0 * w / h;

    Scene.Reshape(global::ratio);
}

static void keyboard(unsigned char k, int x, int y)
{
    switch (k) {
            case 't' : global::theta++; if(global::theta > 360) global::theta = 1; break;
            case 'p' : global::phi++; if(global::phi > 360) global::phi = 1; break;
            case 'T' : global::theta--; if(global::theta < 0) global::theta = 359; break;
            case 'P' : global::phi--; if(global::phi < 0) global::phi = 359; break;
            case  27 : exit(0); break;
    }
}

int main( int argc, char *argv[] )
{
   glutInit( &argc, argv );
   //opengl 3.0 with freeglut requires to install latest version from svn
   //but not necessary to actually get openGL context since code will run anyhow.
   //glutInitContextVersion( 3, 0 ); // freeglut is so cool! get openGL 3.0 context
   //glutInitContextFlags( int flags )
   glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize(global::width, global::height);
   glutCreateWindow("demo opengl 3.0 matrix transformations");

   glewInit();

   assert( Scene.Init() ); // bail if scene initialization fails

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);

   glutMainLoop();

   return 0;
}

Great example!Thanks marshats!!

As an update dealing with the newer headers for openGL 3, I found I had to add the gl3.h header explicitly and a -DGL3_PROTOTYPES on the command line to remove errors at compile time.

Here is the updated code that compiles and runs again:


//on linux or mingw: g++ demo.cpp -lglut -lGLEW -DGL3_PROTOTYPES
// modified to use GLM library from http://pheatt.emporia.edu/courses/2005/cs410f05/hand14/hand14.htm
// modified to use camera at begining of MODELVIEW Transformations, not in the Projection Transform! see http://www.sjbaker.org/steve/omniv/projection_abuse.html
#include <GL/glew.h>     // great opengl extensions helper
#include <GL/gl3.h>
#include <GL/freeglut.h> // use of opengl 3.0 context requires freeglut from svn!

#include <glm/glm.h> //OpenGL Mathematics (GLM).  A C++ mathematics library for 3D graphics.
#include <glm/glmext.h>
#include <glm/GLM_VIRTREV_address.h> // gives helper function address(X) instead of using &X[0][0]
namespace glm
{
          // read glm/gtx/transform.h for function prototypes
          using GLM_GTX_transform;
          using GLM_GTX_transform2; // for lookAt
          using GLM_GTX_matrix_projection;
}
using namespace glm;

#include <cstdio>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stack>
#include <cstring>
#include <cassert>

namespace global {
  int theta = 0;
  int   phi = 0;
  GLfloat ratio = 1.0;
  int width = 512;
  int height = 512;
};

class CustomGraphicsPipeline
{
			GLuint shader_id;
      std::stack<mat4> glm_ProjectionMatrix; //cpu-side
			GLint  glm_ProjectionMatrix_id; //cpu-side hook to shader uniform
      std::stack<mat4> glm_ModelViewMatrix; //cpu-side
			GLint  glm_ModelViewMatrix_id; //cpu-side hook to shader uniform
			GLuint vao_id[2]; // vertex array object hook id
			GLuint vao_elementcount[2]; // number of attribute elements in vao ie number of vertices
			GLuint vao_primitivetype[2]; // type [GL_LINE_LOOP|GL_TRIANGLES|etc] 
		public:
			CustomGraphicsPipeline() :
       shader_id(NULL),
       glm_ProjectionMatrix_id(NULL),
       glm_ModelViewMatrix_id(NULL)
      {
       glm_ProjectionMatrix.push( mat4(1.0f) ); // identity matrix
       glm_ModelViewMatrix.push( mat4(1.0f) ), // identity matrix
       vao_id[0]=NULL; 
       vao_id[1]=NULL;
       vao_elementcount[0]=0; 
       vao_elementcount[1]=0;
       vao_primitivetype[0] = GL_LINE_LOOP;
       vao_primitivetype[1] = GL_TRIANGLES;
      }
			~CustomGraphicsPipeline() {}

      bool Init()										// All Setup For OpenGL Goes Here
      {
        GLint ret = true; // optimistic return value upon completion of execution 

        std::cout << "GL_VERSION: " << glGetString(GL_VERSION) << std::endl;
        std::cout << "GL_EXTENSIONS: " << glGetString(GL_EXTENSIONS) << std::endl;
        std::cout << "GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
        std::cout << "GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
        std::cout << "GLU_VERSION: " << gluGetString(GLU_VERSION) << std::endl;
        std::cout << "GLU_EXTENSIONS: " << gluGetString(GLU_EXTENSIONS) << std::endl;
        std::cout << "GLUT_API_VERSION: " << GLUT_API_VERSION << std::endl;
#ifdef GLUT_XLIB_IMPLEMENTATION
        std::cout << "GLUT_XLIB_IMPLEMENTATION: " << GLUT_XLIB_IMPLEMENTATION << std::endl;
#endif
        std::cout << "press t,T to rotate camera theta" << std::endl;
        std::cout << "press p,P to rotate camera phi" << std::endl;

        glEnable(GL_DEPTH_TEST);
        glClearColor(0.2f, 0.2f, 0.2f, 0.5f);

      //Datas destioned for video memory, can be local (and lost after bound to GPU!). 
        GLfloat vertices0[] = { // dgl_Vertex
          1.0, -1.0, 0.0, 1.0, // xyzw 
         -1.0, -1.0, 0.0, 1.0,
          0.0,  1.0, 0.0, 1.0
        };
        size_t Nbytes_vertices0=sizeof(vertices0);

        GLfloat colors0[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors0=sizeof(colors0);

        GLfloat vertices1[] = { // dgl_Vertex
          0.5, -0.5, 0.0, 1.0, // xyzw 
         -0.5, -0.5, 0.0, 1.0,
          0.0,  0.5, 0.0, 1.0
        }; 
        size_t Nbytes_vertices1=sizeof(vertices1);

        GLfloat colors1[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors1=sizeof(colors1);

        const GLchar *g_vertexShader[] = {"#version 130
",
         "uniform mat4 glm_ProjectionMatrix;
", // replaces deprecated gl_ProjectionMatrix see http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
         "uniform mat4 glm_ModelViewMatrix;
", // replaces deprecated gl_ModelViewMatrix
         "in		 vec4 dgl_Vertex;
", // replaces deprecated gl_Vertex
         "in		 vec4 dgl_Color;
", // replaces deprecated gl_Color
         "invariant out	vec4 Color;
", // to fragment shader
         "void main(void)
",
         "{
",
         "	Color = dgl_Color;
",
         "	gl_Position = glm_ProjectionMatrix*glm_ModelViewMatrix*dgl_Vertex;
", // replaces deprecated ftransform() see http://www.songho.ca/opengl/gl_transform.html
         "}
"
        };

        const GLchar *g_fragmentShader[] = {"#version 130
",
         "invariant in vec4 Color;
", // from vertex shader
         "out  vec4 dgl_FragColor;
", // replaces deprecated gl_FragColor
         "void main(void)
",
         "{
",
         "  dgl_FragColor = Color;
", // gl_FragColor is deprecated
         "}
"
        };
  
      // compile Vertex shader
        GLuint m_vxShaderId = glCreateShader(GL_VERTEX_SHADER);
        GLsizei nlines_vx = sizeof(g_vertexShader)/sizeof(const GLchar*);
        glShaderSource(m_vxShaderId, nlines_vx, (const GLchar**)g_vertexShader, NULL);
        glCompileShader(m_vxShaderId);
        CheckShader(m_vxShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the vertex shader!");

      // compile Fragment shader
        GLuint m_fgShaderId = glCreateShader(GL_FRAGMENT_SHADER);
        GLsizei nlines_fg = sizeof(g_fragmentShader)/sizeof(const GLchar*);
        glShaderSource(m_fgShaderId, nlines_fg, (const GLchar**)g_fragmentShader, NULL);
        glCompileShader(m_fgShaderId);
        CheckShader(m_fgShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the fragment shader!");
	  
      // link shaders
        shader_id = glCreateProgram();
        glAttachShader(shader_id, m_vxShaderId);
        glAttachShader(shader_id, m_fgShaderId);
        glLinkProgram(shader_id);
        CheckShader(shader_id, GL_LINK_STATUS, &ret, "unable to link the program!");
 
      //hooks from CPU to GPU
        //define Uniform hooks
        glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, "glm_ProjectionMatrix");
        glm_ModelViewMatrix_id = glGetUniformLocation(shader_id, "glm_ModelViewMatrix");

        //guard that all attributes have same number of elements
        assert(Nbytes_vertices0/4/sizeof(GLfloat)==Nbytes_colors0/4/sizeof(GLfloat));
        vao_elementcount[0]=Nbytes_vertices0/4/sizeof(GLfloat); // number of elements for first VAO
        assert(Nbytes_vertices1/4/sizeof(GLfloat)==Nbytes_colors1/4/sizeof(GLfloat));
        vao_elementcount[1]=Nbytes_vertices1/4/sizeof(GLfloat); // number of elements for second VAO

        //create and define vertex array objects
        glGenVertexArrays(2, &vao_id[0]); // vao_id[#] will be referenced in Draw()
        defineVertexArrayObject(vao_id[0],Nbytes_vertices0,4,GL_FLOAT,vertices0,colors0); //VertexAttribArray: vertices0, colors0
        defineVertexArrayObject(vao_id[1],Nbytes_vertices1,4,GL_FLOAT,vertices1,colors1); //VertexAttribArray: vertices1, colors1

      // finally, use the shader for rendering 
        glUseProgram(shader_id);            // select the shaders program

        return ret;										// Initialization Went OK?
      }

      void defineVertexArrayObject(GLuint vaoId, size_t Nbytes, GLint size, GLenum type, GLfloat *vertices, GLfloat *colors)
      {
        //enable vertex array object to be defined
        glBindVertexArray(vaoId);

        //generate VBO foreach 'in'; dgl_Vertex and dgl_Color
        GLuint m_vboId[2];
        glGenBuffers(2, &m_vboId[0]);

        //"in		 vec4 dgl_Vertex;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[0] );	// enable the 1st VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes, vertices, GL_STATIC_DRAW); // fill the VBO with vertices data
        const GLuint index_mPosition = glGetAttribLocation(shader_id,"dgl_Vertex"); // get ID for "dgl_Vertex"
        glVertexAttribPointer(index_mPosition, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Vertex" attribute
        glEnableVertexAttribArray(index_mPosition);		// enable VBO vertex attribute ("dgl_Vertex")

        //"in		 vec4 dgl_Color;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[1]);	// enable the 2nd VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes , colors, GL_STATIC_DRAW); // fill the 2nd VBO with colors data
        const GLuint index_mcolor = glGetAttribLocation(shader_id,"dgl_Color"); // get ID for "dgl_Color"
        glVertexAttribPointer(index_mcolor, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Color" attribute
        glEnableVertexAttribArray(index_mcolor);		// enable VBO vertex attribute ("dgl_Color")
      }

      void CheckShader(GLuint id, GLuint type, GLint *ret, const char *onfail)
      {
       //Check if something is wrong with the shader
       switch(type) {
       case(GL_COMPILE_STATUS):
         glGetShaderiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetShaderInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
         break;
       case(GL_LINK_STATUS):
         glGetProgramiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetProgramInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
       default:
         break;
       };
      }

      void Draw_vao(size_t index)
      {
        glBindVertexArray(vao_id[index]);		// select the vertex array object:vao_id[index] by definiton using vertices_index,colors_index
        glDrawArrays(vao_primitivetype[index], 0, vao_elementcount[index]);	// draw the array (at the speed of light)
      }

      void Draw()									// Here's Where We Do All The Drawing
      {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) );	// set the rotation/translation/scale matrix 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        //glm_ModelViewMatrix.top() *= translate(       vec3(0.5, 0.5, 0.0) );
        glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(0.0, 0.0, 1.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );	// set the rotation/translation/scale matrix 

        Draw_vao(0);

        glm_ModelViewMatrix.pop();
        } 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        glm_ModelViewMatrix.top() *= translate(       vec3(0.0, 0.0, 0.25) );
        //glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(1.0, 1.0, 0.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );	// set the rotation/translation/scale matrix 

        Draw_vao(1);

        glm_ModelViewMatrix.pop();
        }
      }
      
      bool Reshape(GLfloat ratio)
      { 
          //glMatrixMode(GL_PROJECTION);
          glm_ProjectionMatrix.top() = mat4(1.0); //glLoadIdentity
          glm_ProjectionMatrix.top() *= perspective(20.0f,ratio,1.0f,3.0f);
      		//glLoadMatrixf(address(glm_ProjectionMatrix.top()));
          glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );	// set the rotation/translation/scale matrix 
      }

      bool SetCamera(GLfloat theta, GLfloat phi)
      { 
        ////////////// 
          // Set the camera view.
          static const double radianFactor = acos(0.0) / 90.0; 
      	  float r = 1.0f*2.0; // approx. want half way between near + far (see perspective)
      	  float eyeX = r * sin(theta * radianFactor) * cos(phi * radianFactor);
      	  float eyeY = r * sin(theta * radianFactor) * sin(phi * radianFactor);
      	  float eyeZ = r * cos(radianFactor * theta);

      	  float centerX = 0, centerY = 0, centerZ = 0;
      	  float upX = 0, upY = 1.0f, upZ = 0;

      	  //glMatrixMode(GL_MODELVIEW);
          glm_ModelViewMatrix.top() = mat4(1.0); // LoadIdentity
          glm_ModelViewMatrix.top() *= lookAt( vec3(eyeX, eyeY, eyeZ), vec3(centerX, centerY, centerZ), vec3(upX, upY, upZ)); 
      		//glLoadMatrixf(address(glm_ModelViewMatrix.top()));
          glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );

        return true; 
      }
};

// GLOBAL ///////////////////////////////////////////////////////////
CustomGraphicsPipeline Scene;
/////////////////////////////////////////////////////////////////////

static void timer(int dt_msec)
{
  static GLfloat time_msec = 0.0;
  time_msec += dt_msec; // absolute time

  Scene.SetCamera(global::theta, global::phi);

	glutPostRedisplay();
	glutTimerFunc(30,timer,30); // come back in 30msec
}

static void display(void) 
{
	Scene.Draw();
  glutSwapBuffers();
}

static void reshape(int w, int h) 
{
    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Prevent a divide by zero, when window is too short
    if(h == 0) h = 1;

    global::width = w;
    global::height = h;
    global::ratio = 1.0 * w / h;

    Scene.Reshape(global::ratio);
}

static void keyboard(unsigned char k, int x, int y)
{
    switch (k) {
            case 't' : global::theta++; if(global::theta > 360) global::theta = 1; break;
            case 'p' : global::phi++; if(global::phi > 360) global::phi = 1; break;
            case 'T' : global::theta--; if(global::theta < 0) global::theta = 359; break;
            case 'P' : global::phi--; if(global::phi < 0) global::phi = 359; break;
            case  27 : exit(0); break;
    }
}

int main( int argc, char *argv[] )
{
   glutInit( &argc, argv );
   //opengl 3.0 with freeglut requires to install latest version from svn
   //but not necessary to actually get openGL context since code will run anyhow.
   //glutInitContextVersion( 3, 0 ); // freeglut is so cool! get openGL 3.0 context
   //glutInitContextFlags( int flags )
   glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize(global::width, global::height);
   glutCreateWindow("demo opengl 3.0 matrix transformations");

   glewInit();

   assert( Scene.Init() ); // bail if scene initialization fails

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);

   glutMainLoop();

   return 0;
}


Hello, is there a similar library for matrix manipulation in C?