0 is a valid uniform location.
If you got a 0 sometimes then surrounding things seem to work.
-1 means the name you asked for was not an active uniform in the program.
This can happen because it’s not there at all or the compiler found that it’s not used in the shader, aka. inactive.
loc = glGetUniformLocationARB(program, "texture");
if (loc != -1) glUniform1iARB(loc, texUnitTexture);
loc = glGetUniformLocationARB(program, "normal");
if (loc != -1) glUniform1iARB(loc, texUnitNormal);
loc = glGetUniformLocationARB(program, "height");
if (loc != -1) glUniform1iARB(loc, texUnitHeight);
Important things to watch out for:
The program needs to be in use when you set the uniforms.
The samplers get texture image unit ids, not texture object ids.
The texture image units need to be setup with a consistent texture. Watch out for the typical mipmap error, default minification filtering is GL_LINEAR_MIPMAP_NEAREST. If you didn’t download a mipmap chain, set the filter to GL_LINEAR or GL_NEAREST for each texture unit.
Texture objects store texture parameters. You need to do that once per texture object and never again, because glBindTexture will update it in the texture unit.
It’s a running integer number from 0 to max. texture image units - 1.
If you bind something to glActiveTexture(GL_TEXTURE0) the sampler needs to be set to integer 0, and so on.
BTW, I think there’s no need to enable the unit, this is texture image units, not texture units.