2D OpenGL tile atlas fragment shader
Why don't you simply set the texture coordinates properly and have a "pass-thru" shader that just samples the texture and nothing else? For example, if you're using glVertexAttribPointer() with an array of vertices and texture coords, make sure that the texture coordinates you send have the proper tile offset. Something like this:

const int numXTiles = 8;
const int numYTiles = 8;
const int numXPixelsPerTile = 16;
const int numYPixelsPerTile = 16;
const int atlasWidth = numXTiles * numXPixelsPerTile;
const int atlasHeight = numYTiles * numYPixelsPerTile;
const double pixelXDelta = 1.0 / atlasWidth;
const double pixelYDelta = 1.0 / atlasHeight;
typedef struct vertex {
    Point3D position;
    Point2D texCoord;
} vertex;
// Assume you're drawing a square and want to texture it with tile 3,4
vertex square[] = {
    { {-1.0, -1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelsPerTile * pixelYDelta } },
    { { 1.0, -1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelPerTile * pixelYDelta } },
    { { 1.0, 1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } },
    { { -1.0, 1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } }
};
glBufferData(GL_ARRAY_BUFFER, 4, square, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, sizeof(vertex), 0); // Position
glVertexAttribPointer(1, 2, GL_FLOAT, sizeof(vertex), (GLvoid*)sizeof(Point3D)); // Texture Coordinate


This assumes your vertex shader has attribute 0 as position and attribute 1 as texture coordinates. Then your fragment shader just becomes:

#version 330 core
in vec2 TexCoord;
out vec4 color;

uniform sampler2D image;

void main()
{
    color = texture(image, TexCoord);
}


NOTE: I may be off by 1 on the right and top side. You might need to subtract 1 pixelXDelta and 1 pixelYDelta from those coordinates - I can never remember.