Do you extend GLSL?
Do you implement includes? Do you implement "target" specification in shader (e.g. which code path to use with "shader model 3.0", with "shader model 4.0", etc.) ... e.g. somewhat extending GLSL to allow as much stuff as HLSL allows us to do.
Yes, I extend it (mostly includes, switches, global constants etc.) using a pre-processor (in my case mcpp). Still you need to remember, that GLSL itself contains some pre-processing powers to handle e.g. different shader model support.
I have a hack job include/prefix system that is just barely workable. Personally I find it absurd that GLSL supports linking but not file includes. If I had time, I'd probably retool with a full parser/effect type system. I've also toyed with simply jumping to hlsl2glsl as a potentially more sane alternative.
How could GLSL even have file includes? GLSL doesn't even know about source files. You would either need a feedback mechanism telling the host application which include file is needed or the host application would have to upload each and every file that might possibly be required by the current source file. To get that right, you would have to parse your GLSL source files anyway to find out which includes you need. It's only a small step towards handling the includes yourself from there.
Linking is a completely different story though, the system knows all symbols generated by its source files and does not need any two-way communication with the host application.
So, I think the way it is done is the only feasible one.
Like Promit, I have a somewhat hacky preprocessor which manages #includes but not much else. For experimental and small scale projects you don't really need anything more. A serious renderer would probably require a more complete system for things like generating shader permutations. External #defines are a good mechanism for that sort of thing.
You don't even need file includes in GLSL; glShaderSource has a pretty good "include" mechanism built-in as is.
const char *globalShaderIncludes = "stuff"; // read this from a file or resource if you want
const char *thisShader = "more stuff"; // load this as normal for the current shader
const char *shaderSources[] = {globalShaderIncludes, thisShader};
glShaderSource (shaderObject, 2, shaderSources, NULL);
I am currently working on simplified GLSL effects, kinda like http://gleffect.sourceforge.net/ but much simpler and focused on GLSL 330 and higher. I am writing it myself to plug it into my engine, I didn't want the external dependencies that GLeffect! includes. I also wanted something that works perfectly with my engine.
Tsk.
You don't even need file includes in GLSL; glShaderSource has a pretty good "include" mechanism built-in as is.
const char *globalShaderIncludes = "stuff"; // read this from a file or resource if you want
const char *thisShader = "more stuff"; // load this as normal for the current shader
const char *shaderSources[] = {globalShaderIncludes, thisShader};
glShaderSource (shaderObject, 2, shaderSources, NULL);
That is what I'm doing and described as a "hack job". It has a variety of practical issues. Here's a hint: where does #version go, particularly when using heterogeneous shader versions? Also, it requires you to remember to do things like add terminating newlines (like a C preprocessor from twenty years ago). It does work, barely.
How could GLSL even have file includes? GLSL doesn't even know about source files. You would either need a feedback mechanism telling the host application which include file is needed
D3DX has done this for many years and many titles have shipped like that. It's a very reasonable approach. As far as I know, there's no OpenGL method of any sort that accepts and uses a callback though. I think there's possibly some reason they've resisted them, because it's the only way to explain...
or the host application would have to upload each and every file that might possibly be required by the current source file. To get that right, you would have to parse your GLSL source files anyway to find out which includes you need.
And that is what they actually did. Seriously, how is such a significant API designed this poorly? It's beyond belief.
Thanks for the input... I'm glad to know that more people think about limitations of GLSL (as opposed to F.e. HLSL).
So far I'm deciding whether I need some more preprocessing than just includes and running specific code for specific shader models (both is already implemented).
I'm gradually coming round to the idea that for anything more than simple demos, writing shaders by hand is for the birds.
A decent graph-based material designer, and a runtime component that generates full shaders from the material definition, is really very pleasant...