First of all, I'd avoid using glut -- it's buggy, hasn't been updated in roughly a decade, and its design doesn't really fit very well with what most people want today (e.g., though you can use it for animations, it's really intended primarily to produce a static display). I pointed out a number of alternatives to glut in a previous answer.
That (mostly) leaves the code to compile, link, and use shaders. I've written a small class I find handy for this purpose:
class shader_prog {
GLuint vertex_shader, fragment_shader, prog;
template <int N>
GLuint compile(GLuint type, char const *(&source)[N]) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, N, source, NULL);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::string log(length, ' ');
glGetShaderInfoLog(shader, length, &length, &log[0]);
throw std::logic_error(log);
return false;
}
return shader;
}
public:
template <int N, int M>
shader_prog(GLchar const *(&v_source)[N], GLchar const *(&f_source)[M]) {
vertex_shader = compile(GL_VERTEX_SHADER, v_source);
fragment_shader = compile(GL_FRAGMENT_SHADER, f_source);
prog = glCreateProgram();
glAttachShader(prog, vertex_shader);
glAttachShader(prog, fragment_shader);
glLinkProgram(prog);
}
operator GLuint() { return prog; }
void operator()() { glUseProgram(prog); }
~shader_prog() {
glDeleteProgram(prog);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
}
};
For a simple demo, a couple of "pass-through" shaders (just imitate the fixed-functionality pipeline):
const GLchar *vertex_shader[] = {
"void main(void) {\n",
" gl_Position = ftransform();\n",
" gl_FrontColor = gl_Color;\n",
"}"
};
const GLchar *color_shader[] = {
"void main() {\n",
" gl_FragColor = gl_Color;\n",
"}"
};
Which you'd use something like:
void draw() {
// compile and link the specified shaders:
static shader_prog prog(vertex_shader, color_shader);
// Use the compiled shaders:
prog();
// Draw something:
glBegin(GL_TRIANGLES);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f, 0.0f, -1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, -1.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3d(0.0, -1.0, -1.0);
glEnd();
}
If you're going to use, for example, a number of different fragment shaders in the course of drawing your scene, you simply define a static object for each, then execute prog1();
, prog2();
, etc., just prior drawing the objects you want shaded with each shader. E.g.,
void draw() {
static shader_prog wall_shader("wall_vertex", "wall_frag");
static shader_prog skin_shader("skin_vertex", "skin_frag");
wall_shader();
draw_walls();
skin_shader();
draw_skin();
}