bertgp already gave you the tip about providing multiple strings to glShaderSource. You can have the first string be “compilation directives/constants” and the second be the actual shader source.
Also, with this, you can generally get much more readable shader code by using shader constants and “if” checks based on them to select branches than by using #define and #if.
For instance, instead of:
#define FOG_MODE VTX_EXP2
...
#if FOG_MODE == VTX_EXP2
...
#endif
Use:
const int FOG_MODE = VTX_EXP2
...
if ( FOG_MODE == VTX_EXP2 )
...
Of course with the latter you need to define int values for each valid value – worth it for the increase in shader readability.
I remember that in CG or the CGFX format you can seletively compile areas of the shader or set constants externally from the shader, maybe similar to passing in uniforms but at compilation.
CG_LITERAL parameters IIRC.
Is there an equivalent in GLSL?
As was mentioned above, not officially. But if you use NVidia’s Cg compiler (cgc) to cross-compile GLSL, you can see that const values are expanded into the shader and used to fold out branches, loops, and such.
Also note that “const” means anything the compiler can infer is “const”, not just those things with a const in front of them. This is a really good thing because there’s currently a quirk in NVidia’s GLSL compiler where you can’t do this:
const int MY_ARRAY[ 2 ] = int( 1, 2 )
You have to drop the const. But NVidia’s compiler is aggressive enough it folds those values in too because it recognizes they’re const.
Note that there are a very few circumstances where you do need to use an #if instead. For instance, if the length of an array would be dynamically computed to be 0, you have to compile it out with #if – because GLSL annoyingly doesn’t accept that as valid… Grr…