I'll start explaining from scratch.
In GLSL, the frag and vert shaders are linked together. It's the linker's task to assign which HW slots are used for inputs, uniform-locations and varyings.
Now, with glBindAttribLoc you can force the linker to use a specific attrib-slot for vtx-attribs. (you must do this _before_ glLinkProgram)
With glUniform1i you specify which texture-unit slot a given texture is used. This is done post-link, but it's also kind of a linking step.
See, so far you can have your code not keep info which was put where - you can enforce those things.
But uniform constants... you must fetch their location. And the returned-value is not a location like 0 for "C0" or 17 for "C17", but an ID. ID of active-uniform. The same uniform can be in both the frag-shader and vert-shader, it's glUniformXXX's task to know and upload in both places in that case.
Then, there's the hellish thing that you can't use glUniform4fv for a mat4x4. You must always use the specific glUniformXXX call to upload to the specific type of constant-data. (or there'll be an error generated). This is really nasty: not only do you have to upload each and every uniform with different calls, but your uniforms will be many too :) .
There's a way to go around it:
//----[ VERTEX UNIFORMS ]------------------------[ struct VVV_FORMAT{ // use this struct in your C++ part, too mat4 MVP; mat4 MV; mat4 P; vec4 ambientColor; vec4 diffuseColor; vec3 norm1; float padding[5]; // gotta align to 64-byte }; uniform mat4 vvv[3]; #define u_MVP vvv[0] #define u_MV vvv[1] #define u_P vvv[2] #define u_ambientColor vvv[3][0] #define u_diffuseColor vvv[3][1] #define u_norm1 vvv[3][2].xyz //-----------------------------------------------/
//----[ FRAGMENT UNIFORMS ]------------------------[ struct FFF_FORMAT{ vec4 color0; vec3 EyeVector; float pad0; }; uniform vec4 fff[2]; #define u_color0 fff[0] #define u_EyeVector fff[1].xyz //-------------------------------------------------/
In your C++ side, you simply keep track of 2 base uniforms' locations: vvv and fff. And of course keep the VVV_FORMAT and FFF_FORMAT structs known and coherent. You upload to the vvv via glUniformMatrix4v() and to the fff via glUniform4fv(). (of course, you can make fff be a mat4 array, too - it'll just be hard to do some loops with manual trick-unpacking in your lighting later)
The only way around this is to use UBOs and the like, with structs packed in layout(std140) uniform { ...... } myUni1;