Shader compilation and mesh drawing could look like this:
struct Shader
{
GLuint vertSh, fragSh;
GLuint program;
};
Shader CompileShader(const char* vertShCode, const char* fragShCode)
{
Shader sh;
// create and compile vertex shader
sh.vertSh=glCreateShader(GL_VERTEX_SHADER);
glShaderSource(sh.vertSh, 1, &vertShCode, NULL);
glCompileShader(sh.vertSh);
// create and compile fragment shader
fh.fragSh=glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(sh.fragSh, 1, &fragShCode, NULL);
glCompileShader(sh.fragSh);
// create, bind attribute locations and link program
sh.program=glCreateProgram();
glAttachShader(sh.program, sh.vertSh);
glAttachShader(sh.program, sh.fragSh);
/*
* Arguments are: program's handle, an index which will be used
* as an argument for glVertexAttribPointer and glEnableVertexAttribArray,
* and a name which identifies the attribute in the vertex shader.
*/
glBindAttribLocation(sh.program, 0, "inPosition");
glBindAttribLocation(sh.program, 1, "inColour");
// other attributes; they must be bound before calling glLinkProgram
glLinkProgram(sh.program);
return sh;
}
void DrawMesh(const Shader& sh, GLuint vbo, GLuint numVertices)
{
glUseProgram(sh.program);
glBindBuffer(GL_ARRAY_BUFFER);
glEnableVertexAttribArray(0); // index, 0 == "inPosition"
glVertexAttribPointer(
0, // index, 0 == "inPosition"
3, // size
false, // normalised
24, // vertex' stride, 3*float for position, and 3*float for colour
0 // offset in the vbo
);
glEnableVertexAttribArray(1); // vertex colour
glVertexAttribPointer(1, 3, false, 24, (void*)12);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
}
I've omitted checking for errors to simplify the code.
Simple vertex shader:
#version 120
// "attribute" instead of "in"
attribute vec3 inPosition;
attribute vec3 inColour;
// "varying" instead of "out"
varying vec3 colour;
void main()
{
gl_Position=vec4(inPosition, 1);
colour=inColour;
}
Simple fragment shader:
#version 120
// "varying" instead of "in"
varying vec3 colour;
void main()
{
gl_FragData[0]=colour;
}
Also, what are the differences between glEnableVertexAttribArray and glEnableClientState, and glVertexAttribPointer and glVertexPointer?
glEnableClientState and glVertexPointer is for fixed function pipline, where vertex attributes were "hard coded" in OpenGL (though you can use them in old GLSL).
glEnableVertexAttribArray, glVertexAttribPointer, and glBindAttribLocation are for modern OpenGL. By using them ( you can specify custom name for each attribute.
The first method was abandoned in new versions of OpenGL, so I suggest using the second one (it is in OpenGL 2.0 core).
But how come using glEnableVertexAttribArray and glVertexAttribPointer
works on Windows but not Linux? And the tutorial even uses this code
without shaders and it still draws the triangle.
Aparently it depends on a specific driver. AFAIK this isn't bound to work. Just a hack to avoid thowing shaders at you from the beginnning.
Also, going a bit off-topic, but is the tutorial teaching fixed-function pipeline? Or is it programmable?
If it teaches shaders, then it teaches programmable pipeline.