Add a ShaderProgram class

Encapsulates compiling, linking, and managing shader attributes; Also update graphics test program to use ShaderProgram
Perhaps, though I think that might be abstraction overkill. In practice you rarely need to combine shaders independent of each other. The main case I'm aware of is for alternate rendering passes, like mixing vertex shader with specialized fragment shaders for selection, depth, etc. But even then, it is trivial and pretty low cost to just copy the source string.