Difference between revisions of "Tutorial1: Rendering shapes with glDrawRangeElements, VAO, VBO, shaders (C++ / freeGLUT)"

From OpenGL Wiki
Jump to: navigation, search
(Created page with "== Overview == This is just a short tutorial about drawing primitives in OpenGL 3.3 without using deprecated functionality. We'll just draw 1 quad (as 2 triangles) and 1 triangle...")
 
m (The Code: added the two "get length" assignments)
 
(6 intermediate revisions by 3 users not shown)
Line 14: Line 14:
 
You can download from http://freeglut.sourceforge.net
 
You can download from http://freeglut.sourceforge.net
  
We'll be using GLEW which will get all the GL function pointers for us. If you are new to GL, read about it at http://www.opengl.org/wiki/Getting_started#OpenGL_2.0.2B_and_extensions
+
We'll be using GLEW which will get all the GL function pointers for us. If you are new to GL, read about it at http://www.opengl.org/wiki/Getting_started#Accessing_OpenGL_functions
  
 
Download GLEW from http://glew.sourceforge.net
 
Download GLEW from http://glew.sourceforge.net
Line 56: Line 56:
 
#include <fstream>
 
#include <fstream>
 
#include <string>
 
#include <string>
 +
#include <sstream>
  
 
using namespace std;
 
using namespace std;
Line 62: Line 63:
  
  
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+
#define BUFFER_OFFSET(i) ((void*)(i))
  
  
Line 138: Line 139:
 
// allocates memory - so need to delete after use
 
// allocates memory - so need to delete after use
 
// size of file returned in fSize
 
// size of file returned in fSize
char* loadFile(const char *fname, GLint &fSize)
+
std::string loadFile(const char *fname)
 
{
 
{
ifstream::pos_type size;
+
std::ifstream file(fname);
char *memblock;
+
if(!file.is_open())
string text;
 
 
 
// file read based on example in cplusplus.com tutorial
 
ifstream file (fname, ios::in|ios::binary|ios::ate);
 
if (file.is_open())
 
{
 
size = file.tellg();
 
fSize = (GLuint) size;
 
memblock = new char[size];
 
file.seekg (0, ios::beg);
 
file.read (memblock, size);
 
file.close();
 
cout << "file " << fname << " loaded" << endl;
 
text.assign(memblock);
 
}
 
else
 
 
{
 
{
 
cout << "Unable to open file " << fname << endl;
 
cout << "Unable to open file " << fname << endl;
Line 163: Line 148:
 
}
 
}
  
return memblock;
+
std::stringstream fileData;
 +
fileData << file.rdbuf();
 +
file.close();
 +
 
 +
return fileData.str();
 
}
 
}
  
Line 221: Line 210:
 
vertexShader=0;
 
vertexShader=0;
 
fragmentShader=0;
 
fragmentShader=0;
 
char *vertexShaderString, *fragmentShaderString;
 
 
vertexShader = glCreateShader(GL_VERTEX_SHADER);
 
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
  
 
// load shaders & get length of each
 
// load shaders & get length of each
 
int vlen;
 
int vlen;
 
int flen;
 
int flen;
vertexShaderString = loadFile(pfilePath_vs, vlen);
+
std::string vertexShaderString = loadFile(pfilePath_vs);
fragmentShaderString = loadFile(pfilePath_fs, flen);
+
std::string fragmentShaderString = loadFile(pfilePath_fs);
 +
vlen = vertexShaderString.length();
 +
flen = fragmentShaderString.length();
  
if(vertexShaderString==NULL)
+
if(vertexShaderString.empty())
 
{
 
{
glDeleteShader(vertexShader);
 
vertexShader=0;
 
glDeleteShader(fragmentShader);
 
fragmentShader=0;
 
 
 
return -1;
 
return -1;
 
}
 
}
  
if(fragmentShaderString==NULL)
+
if(fragmentShaderString.empty())
 
{
 
{
glDeleteShader(vertexShader);
+
return -1;
vertexShader=0;
+
}
glDeleteShader(fragmentShader);
 
fragmentShader=0;
 
  
delete [] vertexShaderString;
+
vertexShader = glCreateShader(GL_VERTEX_SHADER);
 +
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  
return -1;
+
const char *vertexShaderCStr = vertexShaderString.c_str();
}
+
const char *fragmentShaderCStr = fragmentShaderString.c_str();
 +
glShaderSource(vertexShader, 1, (const GLchar **)&vertexShaderCStr, &vlen);
 +
glShaderSource(fragmentShader, 1, (const GLchar **)&fragmentShaderCStr, &flen);
  
glShaderSource(vertexShader, 1, (const GLchar **)&vertexShaderString, &vlen);
 
glShaderSource(fragmentShader, 1, (const GLchar **)&fragmentShaderString, &flen);
 
 
 
GLint compiled;
 
GLint compiled;
  
Line 271: Line 250:
 
glDeleteShader(fragmentShader);
 
glDeleteShader(fragmentShader);
 
fragmentShader=0;
 
fragmentShader=0;
 
delete [] vertexShaderString;
 
delete [] fragmentShaderString;
 
  
 
return -1;
 
return -1;
Line 289: Line 265:
 
glDeleteShader(fragmentShader);
 
glDeleteShader(fragmentShader);
 
fragmentShader=0;
 
fragmentShader=0;
 
delete [] vertexShaderString;
 
delete [] fragmentShaderString;
 
  
 
return -1;
 
return -1;
Line 321: Line 294:
  
 
GLint maxLength;
 
GLint maxLength;
char *pLinkInfoLog;
 
 
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
 
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
 
if(maxLength>0)
 
if(maxLength>0)
 
{
 
{
pLinkInfoLog=new char[maxLength];
+
char *pLinkInfoLog = new char[maxLength];
 
glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, pLinkInfoLog);
 
glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, pLinkInfoLog);
cout<<pLinkInfoLog<<endl;
+
cout << pLinkInfoLog << endl;
 
delete [] pLinkInfoLog;
 
delete [] pLinkInfoLog;
 
}
 
}
Line 339: Line 311:
 
glDeleteProgram(shaderProgram);
 
glDeleteProgram(shaderProgram);
 
shaderProgram=0;
 
shaderProgram=0;
 
delete [] vertexShaderString;
 
delete [] fragmentShaderString;
 
  
 
return -1;
 
return -1;
 
}
 
}
 
delete [] vertexShaderString;
 
delete [] fragmentShaderString;
 
  
 
return 1; //Success
 
return 1; //Success
Line 355: Line 321:
 
{
 
{
 
//A quad
 
//A quad
pvertex_quad[0].x=-0.8;
+
pvertex_quad[0].x=-0.8f;
pvertex_quad[0].y=-0.5;
+
pvertex_quad[0].y=-0.5f;
pvertex_quad[0].z=-0.9;
+
pvertex_quad[0].z=-0.9f;
 
pvertex_quad[0].color=0xFFFFFFFF;
 
pvertex_quad[0].color=0xFFFFFFFF;
  
pvertex_quad[1].x=0.0;
+
pvertex_quad[1].x=0.0f;
pvertex_quad[1].y=-0.5;
+
pvertex_quad[1].y=-0.5f;
pvertex_quad[1].z=-0.9;
+
pvertex_quad[1].z=-0.9f;
 
pvertex_quad[1].color=0xFFFF0000;
 
pvertex_quad[1].color=0xFFFF0000;
  
pvertex_quad[2].x=-0.8;
+
pvertex_quad[2].x=-0.8f;
pvertex_quad[2].y=0.5;
+
pvertex_quad[2].y=0.5f;
pvertex_quad[2].z=-0.9;
+
pvertex_quad[2].z=-0.9f;
 
pvertex_quad[2].color=0xFF00FF00;
 
pvertex_quad[2].color=0xFF00FF00;
  
pvertex_quad[3].x=0.0;
+
pvertex_quad[3].x=0.0f;
pvertex_quad[3].y=0.5;
+
pvertex_quad[3].y=0.5f;
pvertex_quad[3].z=-0.9;
+
pvertex_quad[3].z=-0.9f;
 
pvertex_quad[3].color=0xFF0000FF;
 
pvertex_quad[3].color=0xFF0000FF;
  
Line 383: Line 349:
  
 
//The triangle
 
//The triangle
pvertex_triangle[0].x=0.0;
+
pvertex_triangle[0].x=0.0f;
pvertex_triangle[0].y=0.5;
+
pvertex_triangle[0].y=0.5f;
pvertex_triangle[0].z=-1.0;
+
pvertex_triangle[0].z=-1.0f;
pvertex_triangle[0].nx=0.0;
+
pvertex_triangle[0].nx=0.0f;
pvertex_triangle[0].ny=0.0;
+
pvertex_triangle[0].ny=0.0f;
pvertex_triangle[0].nz=1.0;
+
pvertex_triangle[0].nz=1.0f;
pvertex_triangle[0].s0=0.0;
+
pvertex_triangle[0].s0=0.0f;
pvertex_triangle[0].t0=0.0;
+
pvertex_triangle[0].t0=0.0f;
  
pvertex_triangle[1].x=0.3;
+
pvertex_triangle[1].x=0.3f;
pvertex_triangle[1].y=-0.5;
+
pvertex_triangle[1].y=-0.5f;
pvertex_triangle[1].z=-1.0;
+
pvertex_triangle[1].z=-1.0f;
pvertex_triangle[1].nx=0.0;
+
pvertex_triangle[1].nx=0.0f;
pvertex_triangle[1].ny=0.0;
+
pvertex_triangle[1].ny=0.0f;
pvertex_triangle[1].nz=1.0;
+
pvertex_triangle[1].nz=1.0f;
pvertex_triangle[1].s0=1.0;
+
pvertex_triangle[1].s0=1.0f;
pvertex_triangle[1].t0=0.0;
+
pvertex_triangle[1].t0=0.0f;
  
pvertex_triangle[2].x=0.8;
+
pvertex_triangle[2].x=0.8f;
pvertex_triangle[2].y=0.5;
+
pvertex_triangle[2].y=0.5f;
pvertex_triangle[2].z=-1.0;
+
pvertex_triangle[2].z=-1.0f;
pvertex_triangle[2].nx=0.0;
+
pvertex_triangle[2].nx=0.0f;
pvertex_triangle[2].ny=0.0;
+
pvertex_triangle[2].ny=0.0f;
pvertex_triangle[2].nz=1.0;
+
pvertex_triangle[2].nz=1.0f;
pvertex_triangle[2].s0=0.5;
+
pvertex_triangle[2].s0=0.5f;
pvertex_triangle[2].t0=1.0;
+
pvertex_triangle[2].t0=1.0f;
  
 
pindex_triangle[0]=0;
 
pindex_triangle[0]=0;
Line 524: Line 490:
 
//Draw command
 
//Draw command
 
//The first to last vertex is 0 to 3
 
//The first to last vertex is 0 to 3
//4 indices will be used to render the 2 triangles. This make our quad.
+
//6 indices will be used to render the 2 triangles. This make our quad.
 
//The last parameter is the start address in the IBO => zero
 
//The last parameter is the start address in the IBO => zero
glDrawRangeElements(GL_TRIANGLES, 0, 3, 4, GL_UNSIGNED_SHORT, NULL);
+
glDrawRangeElements(GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, NULL);
  
 
//Bind the shader that we want to use
 
//Bind the shader that we want to use
Line 759: Line 725:
 
}
 
}
 
</source>
 
</source>
 +
[[Category:Tutorials]]

Latest revision as of 14:19, 16 May 2012

Overview

This is just a short tutorial about drawing primitives in OpenGL 3.3 without using deprecated functionality. We'll just draw 1 quad (as 2 triangles) and 1 triangle.

You can use any C++ compiler on any OS.

The code demonstrates a few key features :

All geometry is uploaded to IBO/VBO. We also wrap these up in a VAO. Rendering is done with glDrawRangeElements instead of the typical glDrawArrays or glDrawElements. The shaders are GL 3.3 specific although they can easily be ported to 3.2 or 3.1 or 3.0 or 2.1 and 2.0.

We are using freeGLUT which is similar to GLUT except it is open source and also up to date.

We'll be calling glutInitContextVersion(3, 3) and glutInitContextFlags(GLUT_CORE_PROFILE).

You can download from http://freeglut.sourceforge.net

We'll be using GLEW which will get all the GL function pointers for us. If you are new to GL, read about it at http://www.opengl.org/wiki/Getting_started#Accessing_OpenGL_functions

Download GLEW from http://glew.sourceforge.net

The Code

The entire code is a single C++ file. Copy it to your computer.

As for the shaders, there are 4 files. Copy them to your computer. Name them Shader1.vert, Shader1.frag, Shader2.vert, Shader2.frag.

Some things to note are that I don't know what would happen if you call glutInitContextVersion(3, 3) on a computer that doesn't support GL 3.3. The documentation doesn't say anything http://freeglut.sourceforge.net/docs/api.php

We are also using __glutCreateWindowWithExit so that we could clean up when the program exits, but it doesn't seem to work.

So we use __glutCreateWindowWithExit to create the window and it also sets up the GL 3.3 context. Then we init GLEW and this is what gets the function pointers. We then just get the GL version and run a dummy code that checks extensions. We then load all shaders, create the geometry and render the scene.

The vertex format for the quad is VC which means vertex and color. The vertices are float x, y, z. The color is unsigned int and RGBA. The shader outputs the RGBA color. You'll see a nicely colored quad.

The vertex format for the triangle is VNT which means vertex, normal and texcoord. We aren't using texcoords in this example. The normals are used for a simple lighting.

//In this example, we will use a few IBO/VBO and a few VAO.
//We will use glDrawRangeElements to render some shapes.
//We will use a couple of simple shaders. GL 3.3 shaders.
//We will create a 3.3 forward context with freeGLUT.
//
//We are using GLEW to get function pointers.
//
//As for the VBO, we will use an interleaved vertex format.
//Vertex, texcoords and normals.
//Vertex and color.
//
//As for the IBO, we will use 16 bit unsigned integers.
//
//http://freeglut.sourceforge.net
//http://glew.sourceforge.net


#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;




#define BUFFER_OFFSET(i) ((void*)(i))





//Vertex, tex0
//
//SIZE : 4+4+4 +4+4 = 4*6 = 20 bytes
//It's better to make it multiple of 32
//32-20 = 12 bytes (of garbage should be added)
//12/4 = 3 floats should be added
struct TVertex_VT
{
	float	x, y, z;
	float	s0, t0;
	float	padding[3];
};

//Vertex, normal, tex0
//
//SIZE : 4+4+4 +4+4+4 +4+4 = 4*8 = 32 bytes
struct TVertex_VNT
{
	float	x, y, z;
	float	nx, ny, nz;
	float	s0, t0;
};

//Vertex, color
//
//SIZE : 4+4+4 +4 = 4*4 = 16 bytes
//It's better to make it multiple of 32
//32-16 = 16 bytes (of garbage should be added)
//16/4 = 4 floats should be added
struct TVertex_VC
{
	float	x, y, z;
	unsigned int	color;
	float	padding[4];
};




//Globals

//A quad
GLushort	pindex_quad[6];
TVertex_VC	pvertex_quad[4];

//A triangle
GLushort		pindex_triangle[3];
TVertex_VNT		pvertex_triangle[3];

//1 VAO for the quad
//1 VAO for the triangle
GLuint VAOID[2];
//1 IBO for the quad (Index Buffer Object)
//1 IBO for the triangle
GLuint IBOID[2];
//1 IBO for the quad (Vertex Buffer Object)
//1 IBO for the triangle
GLuint VBOID[2];

//1 shader for the quad
//1 shader for the triangle
GLuint	ShaderProgram[2];
GLuint	VertexShader[2];
GLuint	FragmentShader[2];

int ProjectionModelviewMatrix_Loc[2];		//The location of ProjectionModelviewMatrix in the shaders

// loadFile - loads text file into char* fname
// allocates memory - so need to delete after use
// size of file returned in fSize
std::string loadFile(const char *fname)
{
	std::ifstream file(fname);
	if(!file.is_open())
	{
		cout << "Unable to open file " << fname << endl;
		exit(1);
	}

	std::stringstream fileData;
	fileData << file.rdbuf();
	file.close();

	return fileData.str();
}


// printShaderInfoLog
// From OpenGL Shading Language 3rd Edition, p215-216
// Display (hopefully) useful error messages if shader fails to compile
void printShaderInfoLog(GLint shader)
{
	int infoLogLen = 0;
	int charsWritten = 0;
	GLchar *infoLog;

	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);

	if (infoLogLen > 0)
	{
		infoLog = new GLchar[infoLogLen];
		// error check for fail to allocate memory omitted
		glGetShaderInfoLog(shader, infoLogLen, &charsWritten, infoLog);
		cout << "InfoLog : " << endl << infoLog << endl;
		delete [] infoLog;
	}
}


void InitGLStates()
{
	glShadeModel(GL_SMOOTH);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glReadBuffer(GL_BACK);
	glDrawBuffer(GL_BACK);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDepthMask(TRUE);
	glDisable(GL_STENCIL_TEST);
	glStencilMask(0xFFFFFFFF);
	glStencilFunc(GL_EQUAL, 0x00000000, 0x00000001);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	glFrontFace(GL_CCW);
	glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);
	glClearColor(1.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0);
	glClearStencil(0);
	glDisable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glDisable(GL_DITHER);
	glActiveTexture(GL_TEXTURE0);
}



int LoadShader(const char *pfilePath_vs, const char *pfilePath_fs, bool bindTexCoord0, bool bindNormal, bool bindColor, GLuint &shaderProgram, GLuint &vertexShader, GLuint &fragmentShader)
{
	shaderProgram=0;
	vertexShader=0;
	fragmentShader=0;

	// load shaders & get length of each
	int vlen;
	int flen;
	std::string vertexShaderString = loadFile(pfilePath_vs);
	std::string fragmentShaderString = loadFile(pfilePath_fs);
	vlen = vertexShaderString.length();
	flen = fragmentShaderString.length();

	if(vertexShaderString.empty())
	{
		return -1;
	}

	if(fragmentShaderString.empty())
	{
		return -1;
	}

	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);	

	const char *vertexShaderCStr = vertexShaderString.c_str();
	const char *fragmentShaderCStr = fragmentShaderString.c_str();
	glShaderSource(vertexShader, 1, (const GLchar **)&vertexShaderCStr, &vlen);
	glShaderSource(fragmentShader, 1, (const GLchar **)&fragmentShaderCStr, &flen);

	GLint compiled;

	glCompileShader(vertexShader);
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &compiled);
	if(compiled==FALSE)
	{
		cout << "Vertex shader not compiled." << endl;
		printShaderInfoLog(vertexShader);

		glDeleteShader(vertexShader);
		vertexShader=0;
		glDeleteShader(fragmentShader);
		fragmentShader=0;

		return -1;
	}

	glCompileShader(fragmentShader);
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &compiled);
	if(compiled==FALSE)
	{
		cout << "Fragment shader not compiled." << endl;
		printShaderInfoLog(fragmentShader);

		glDeleteShader(vertexShader);
		vertexShader=0;
		glDeleteShader(fragmentShader);
		fragmentShader=0;

		return -1;
	}

	shaderProgram = glCreateProgram();

	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);

	glBindAttribLocation(shaderProgram, 0, "InVertex");

	if(bindTexCoord0)
		glBindAttribLocation(shaderProgram, 1, "InTexCoord0");

	if(bindNormal)
		glBindAttribLocation(shaderProgram, 2, "InNormal");

	if(bindColor)
		glBindAttribLocation(shaderProgram, 3, "InColor");

	glLinkProgram(shaderProgram);

	GLint IsLinked;
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, (GLint *)&IsLinked);
	if(IsLinked==FALSE)
	{
		cout << "Failed to link shader." << endl;

		GLint maxLength;
		glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
		if(maxLength>0)
		{
			char *pLinkInfoLog = new char[maxLength];
			glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, pLinkInfoLog);
			cout << pLinkInfoLog << endl;
			delete [] pLinkInfoLog;
		}

		glDetachShader(shaderProgram, vertexShader);
		glDetachShader(shaderProgram, fragmentShader);
		glDeleteShader(vertexShader);
		vertexShader=0;
		glDeleteShader(fragmentShader);
		fragmentShader=0;
		glDeleteProgram(shaderProgram);
		shaderProgram=0;

		return -1;
	}

	return 1;		//Success
}

void CreateGeometry()
{
	//A quad
	pvertex_quad[0].x=-0.8f;
	pvertex_quad[0].y=-0.5f;
	pvertex_quad[0].z=-0.9f;
	pvertex_quad[0].color=0xFFFFFFFF;

	pvertex_quad[1].x=0.0f;
	pvertex_quad[1].y=-0.5f;
	pvertex_quad[1].z=-0.9f;
	pvertex_quad[1].color=0xFFFF0000;

	pvertex_quad[2].x=-0.8f;
	pvertex_quad[2].y=0.5f;
	pvertex_quad[2].z=-0.9f;
	pvertex_quad[2].color=0xFF00FF00;

	pvertex_quad[3].x=0.0f;
	pvertex_quad[3].y=0.5f;
	pvertex_quad[3].z=-0.9f;
	pvertex_quad[3].color=0xFF0000FF;

	pindex_quad[0]=0;
	pindex_quad[1]=1;
	pindex_quad[2]=2;
	pindex_quad[3]=2;
	pindex_quad[4]=1;
	pindex_quad[5]=3;

	//The triangle
	pvertex_triangle[0].x=0.0f;
	pvertex_triangle[0].y=0.5f;
	pvertex_triangle[0].z=-1.0f;
	pvertex_triangle[0].nx=0.0f;
	pvertex_triangle[0].ny=0.0f;
	pvertex_triangle[0].nz=1.0f;
	pvertex_triangle[0].s0=0.0f;
	pvertex_triangle[0].t0=0.0f;

	pvertex_triangle[1].x=0.3f;
	pvertex_triangle[1].y=-0.5f;
	pvertex_triangle[1].z=-1.0f;
	pvertex_triangle[1].nx=0.0f;
	pvertex_triangle[1].ny=0.0f;
	pvertex_triangle[1].nz=1.0f;
	pvertex_triangle[1].s0=1.0f;
	pvertex_triangle[1].t0=0.0f;

	pvertex_triangle[2].x=0.8f;
	pvertex_triangle[2].y=0.5f;
	pvertex_triangle[2].z=-1.0f;
	pvertex_triangle[2].nx=0.0f;
	pvertex_triangle[2].ny=0.0f;
	pvertex_triangle[2].nz=1.0f;
	pvertex_triangle[2].s0=0.5f;
	pvertex_triangle[2].t0=1.0f;

	pindex_triangle[0]=0;
	pindex_triangle[1]=1;
	pindex_triangle[2]=2;


	//Create the IBO for the quad
	//16 bit indices
	glGenBuffers(1, &IBOID[0]);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOID[0]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(GLushort), pindex_quad, GL_STATIC_DRAW);

	GLenum error=glGetError();

	//Create the IBO for the triangle
	//16 bit indices
	//We could have actually made one big IBO for both the quad and triangle.
	glGenBuffers(1, &IBOID[1]);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOID[1]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3*sizeof(GLushort), pindex_triangle, GL_STATIC_DRAW);

	error=glGetError();

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	error=glGetError();

	//Create VBO for the quad
	glGenBuffers(1, &VBOID[0]);
	glBindBuffer(GL_ARRAY_BUFFER, VBOID[0]);
	glBufferData(GL_ARRAY_BUFFER, 4*sizeof(TVertex_VC), pvertex_quad, GL_STATIC_DRAW);

	error=glGetError();

	//Just testing
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	//Create VBO for the triangle
	glGenBuffers(1, &VBOID[1]);

	glBindBuffer(GL_ARRAY_BUFFER, VBOID[1]);
	glBufferData(GL_ARRAY_BUFFER, 3*sizeof(TVertex_VNT), pvertex_triangle, GL_STATIC_DRAW);

	//Just testing
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	error=glGetError();

	//VAO for the quad *********************
	glGenVertexArrays(1, &VAOID[0]);
	glBindVertexArray(VAOID[0]);

	//Bind the VBO and setup pointers for the VAO
	glBindBuffer(GL_ARRAY_BUFFER, VBOID[0]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VC), BUFFER_OFFSET(0));
	glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(TVertex_VC), BUFFER_OFFSET(sizeof(float)*3));
	glEnableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glEnableVertexAttribArray(3);

	//Bind the IBO for the VAO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOID[0]);

	//Second VAO setup *******************
	//This is for the triangle
	glGenVertexArrays(1, &VAOID[1]);
	glBindVertexArray(VAOID[1]);

	//Bind the VBO and setup pointers for the VAO
	glBindBuffer(GL_ARRAY_BUFFER, VBOID[1]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNT), BUFFER_OFFSET(0));
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNT), BUFFER_OFFSET(sizeof(float)*3));
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNT), BUFFER_OFFSET(sizeof(float)*6));
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(2);
	glDisableVertexAttribArray(3);

	//Bind the IBO for the VAO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOID[1]);

	//Just testing
	glBindVertexArray(0);
	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glDisableVertexAttribArray(3);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void display()
{
	float projectionModelviewMatrix[16];

	//Just set it to identity matrix
	memset(projectionModelviewMatrix, 0, sizeof(float)*16);
	projectionModelviewMatrix[0]=1.0;
	projectionModelviewMatrix[5]=1.0;
	projectionModelviewMatrix[10]=1.0;
	projectionModelviewMatrix[15]=1.0;

	//Clear all the buffers
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	//Bind the shader that we want to use
	glUseProgram(ShaderProgram[0]);
	//Setup all uniforms for your shader
	glUniformMatrix4fv(ProjectionModelviewMatrix_Loc[0], 1, FALSE, projectionModelviewMatrix);
	//Bind the VAO
	glBindVertexArray(VAOID[0]);
	//At this point, we would bind textures but we aren't using textures in this example

	//Draw command
	//The first to last vertex is 0 to 3
	//6 indices will be used to render the 2 triangles. This make our quad.
	//The last parameter is the start address in the IBO => zero
	glDrawRangeElements(GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, NULL);

	//Bind the shader that we want to use
	glUseProgram(ShaderProgram[1]);
	//Setup all uniforms for your shader
	glUniformMatrix4fv(ProjectionModelviewMatrix_Loc[1], 1, FALSE, projectionModelviewMatrix);
	//Bind the VAO
	glBindVertexArray(VAOID[1]);
	//At this point, we would bind textures but we aren't using textures in this example

	//Draw command
	//The first to last vertex is 0 to 3
	//3 indices will be used to render 1 triangle.
	//The last parameter is the start address in the IBO => zero
	glDrawRangeElements(GL_TRIANGLES, 0, 3, 3, GL_UNSIGNED_SHORT, NULL);

	glutSwapBuffers();
}

void reshape(int w, int h)
{
	glViewport(0, 0, w, h);
}

void ExitFunction(int value)
{
	cout<<"Exit called."<<endl;

	glBindVertexArray(0);
	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glDisableVertexAttribArray(3);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glUseProgram(0);

	glDeleteBuffers(1, &IBOID[0]);
	glDeleteBuffers(1, &IBOID[1]);
	glDeleteBuffers(1, &VBOID[0]);
	glDeleteBuffers(1, &IBOID[1]);
	glDeleteVertexArrays(1, &VAOID[0]);
	glDeleteVertexArrays(1, &VAOID[1]);

	glDetachShader(ShaderProgram[0], VertexShader[0]);
	glDetachShader(ShaderProgram[0], FragmentShader[0]);
	glDeleteShader(VertexShader[0]);
	glDeleteShader(FragmentShader[0]);
	glDeleteProgram(ShaderProgram[0]);

	glDetachShader(ShaderProgram[1], VertexShader[1]);
	glDetachShader(ShaderProgram[1], FragmentShader[1]);
	glDeleteShader(VertexShader[1]);
	glDeleteShader(FragmentShader[1]);
	glDeleteProgram(ShaderProgram[1]);
}

int main (int argc, char* argv[])
{
	int i;
	int NumberOfExtensions;
	int OpenGLVersion[2];

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
	//We want to make a GL 3.3 context
	glutInitContextVersion(3, 3);
	glutInitContextFlags(GLUT_CORE_PROFILE);
	glutInitWindowPosition(100, 50);
	glutInitWindowSize(600, 600);
	__glutCreateWindowWithExit("GL 3.3 Test", ExitFunction);

	//Currently, GLEW uses glGetString(GL_EXTENSIONS) which is not legal code
	//in GL 3.3, therefore GLEW would fail if we don't set this to TRUE.
	//GLEW will avoid looking for extensions and will just get function pointers for all GL functions.
	glewExperimental=TRUE;
	GLenum err=glewInit();
	if(err!=GLEW_OK)
	{
		//Problem: glewInit failed, something is seriously wrong.
		cout<<"glewInit failed, aborting."<<endl;
		exit(1);
	}

	//The old way of getting the GL version
	//This will give you something like 3.3.2895 WinXP SSE
	//where the 3.3 would be the version number and the rest is vendor
	//dependent information.
	//In this case, 2895 is a build number.
	//Then the OS : WinXP
	//Then CPU features such as SSE
	cout<<"OpenGL version = "<<glGetString(GL_VERSION)<<endl;

	//This is the new way for getting the GL version.
	//It returns integers. Much better than the old glGetString(GL_VERSION).
	glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
	glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);
	cout<<"OpenGL major version = "<<OpenGLVersion[0]<<endl;
	cout<<"OpenGL minor version = "<<OpenGLVersion[1]<<endl<<endl;

	//The old method to get the extension list is obsolete.
	//You must use glGetIntegerv and glGetStringi
	glGetIntegerv(GL_NUM_EXTENSIONS, &NumberOfExtensions);

	//We don't need any extensions. Useless code.
	for(i=0; i<NumberOfExtensions; i++)
	{
		const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
	}

	InitGLStates();

	if(LoadShader("Shader1.vert", "Shader1.frag", false, false, true, ShaderProgram[0], VertexShader[0], FragmentShader[0])==-1)
	{
		exit(1);
	}
	else
	{
		ProjectionModelviewMatrix_Loc[0]=glGetUniformLocation(ShaderProgram[0], "ProjectionModelviewMatrix");
	}

	if(LoadShader("Shader2.vert", "Shader2.frag", true, true, false, ShaderProgram[1], VertexShader[1], FragmentShader[1])==-1)
	{
		exit(1);
	}
	else
	{
		ProjectionModelviewMatrix_Loc[1]=glGetUniformLocation(ShaderProgram[1], "ProjectionModelviewMatrix");
	}

	CreateGeometry();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);

	glutMainLoop();
	return 0;
}

Shader1.vert : notice that we have 1 uniform called ProjectionModelviewMatrix. We set this to identity in our C++ code.

The color has the smooth qualifier which will instruct the GPU to do bilinear interpolation across the polygon.

InVertex and InColor are attributes which are setup with a call to glBindAttribLocation. After that, you must link the shader and check for success (glLinkProgram and glGetProgramiv(shaderProgram, GL_LINK_STATUS, (GLint *)&IsLinked))

//[VERTEX SHADER]
#version 330

in vec3 InVertex;
in vec4 InColor;


smooth out vec4 Color;

uniform mat4 ProjectionModelviewMatrix;


void main()
{
	gl_Position = ProjectionModelviewMatrix * vec4(InVertex, 1.0);
	Color = InColor;
}

Shader1.frag : here we have the input Color. We just write it out to FragColor. FragColor is our own output variable which GL automatically bind to output 0, therefore we don't need to set it up from our C++ side of the code.

//[FRAGMENT SHADER]
#version 330


smooth in vec4 Color;


out vec4 FragColor;


void main()
{
	FragColor = Color;
}

Shader2.vert

//[VERTEX SHADER]
#version 330

in vec3 InVertex;
in vec3 InNormal;


smooth out vec3 LightVector0;
smooth out vec3 EyeNormal;

uniform mat4 ProjectionModelviewMatrix;


void main()
{
	gl_Position = ProjectionModelviewMatrix * vec4(InVertex, 1.0);

	LightVector0 = vec3(1.0, 1.0, 1.0);
	EyeNormal = InNormal;
}

Shader2.frag

//[FRAGMENT SHADER]
#version 330

smooth in vec3 LightVector0;
smooth in vec3 EyeNormal;

out vec4 FragColor;


void main()
{
	vec3 eyeNormal;
	vec3 lightVector;
	float dotProduct;

	eyeNormal = normalize(EyeNormal);
	lightVector = normalize(LightVector0);

	dotProduct = dot(eyeNormal, lightVector);

	FragColor = vec4(dotProduct);
}