Oops, clumsy of me. I had that originally set up for just handling the 2x4 diffuse/bump/specular matrixes, and made the change to more generic matrix handling quite late. At least that's what I'm telling my lawyer.
layout (location=n) can be omitted - you'd use an attribute location table in the C++ code instead and pass that as a param to the shader creation function, calling glBindAttribLocation based on the contents of the table. The only thing to be careful of is to make the glBindAttribLocation calls after the shaders have been attached but before the program has been linked. There's an example implementation of this in my first version (on pastebin, with the non-GPL-friendly shaders).
Alternatively you could scrap generic attrib arrays and use glTexCoordPointer calls instead (being careful to use glClientActiveTexture too - note that the stock code uses GL_SelectTextureNoClient so change that to GL_SelectTexture and specify the arrays following each Bind). I'd be personally more inclined to keep generic arrays though.
I think layout (location=n) is a GL3.x+ feature, but I wasn't able to find definite confirmation of which version it went core in; it's also available via GL_ARB_explicit_attrib_location on earlier versions. Non-square matrixes are GL2.1 and I don't think there's an extension for it. The lack of a GL_ARB_explicit_uniform_location is shocking and not being able to specify default values for sampler uniforms is also crap. GLSL's behaviour for both of these gives nothing of real value and just piles up the supporting infrastructure needed before you can get down to the fun part (actually writing shaders). HLSL's ": register(c0)" setup is infinitely superior in practice.
Laughing at the fact that AMD were happy without a #version but NV choked on it - it's normally the other way around. I guess NV have been tightening up on spec conformance lately.
It should be easy enough to extend this code to handle user-defined materials, but the material shader would need to be written in GLSL. When draw time comes check a flag on the material to determine it's type and send it through the appropriate path. The overhead of constantly enabling/disabling different shader modes may pile up though. By then you definitely need something like an RB_SelectShaderMode call that just selects the appropriate mode - the stock Doom 3 code will often disable shaders entirely at the end of one draw pass only to just re-enable them again at the start of the next one. The more you switch shader modes the more this will cause perf trouble, so better to cache the current mode and only switch (or enable/disable) if actually needed.
Doing an ARB to GLSL parser would be a lot more work, as would be implementing GLSL versions of the other ARB shaders, in particular because there are no alternate shader paths provided for them so there's nothing to derive a GPL-friendly version from. For ARB-to-GLSL the lack of explicit uniform locations and default sampler values in GLSL are particularly going to cause huge trouble - because ARB has both, so things would be a bit wild west with GLSL, and the resulting shader would need to be quite tightly coupled to the C++ code to work around it.
What seems more interesting is doing shader implementations of the remaining fixed-pipeline paths in the engine - the stuff in RB_STD_T_RenderShaderPasses should convert quite well to a single generic vertex/fragment shader pair.
As always with Doom 3, the turnaround time between initially writing code and actually getting to test it in the engine is incredibly long - lots of code, glacial compile times, slow loading don't make for easy and rapid iteration of changes. This makes wide-ranging changes more annoying than they otherwise would be.