Three vertices, three coordinate pairs
Texture coordinate triangle
Texture coordinates are a vertex attribute, exactly like position or colour — each vertex carries one (s,t) pair, and the rasteriser interpolates between them across the triangle. Drag the handles on either side: the left triangle picks a region out of the image, the right one says where it lands. The code underneath is what you would have written.
In the texture — (s,t)
Drag a handle
vertex 0
vertex 1
vertex 2
On the surface — (x,y)
These handles move too
The image region is stretched to fit whatever shape you give it. Nothing forces the two triangles to be the same shape — that mismatch is the distortion.
The code
Note the ordering: glTexCoord2d sets a piece of current state, and the following glVertex2d consumes it. Call them the other way round and the vertex picks up the previous vertex's coordinates.
Source area (of the image)
—
Magnification
—
Orientation
—
Interpolated (s,t) at pointer
—
Why the pointer readout matters. Move over the right-hand triangle and watch the coordinate readout change smoothly. Nobody stored those values — only three pairs were ever specified, at the corners. Everything between them is produced by the rasteriser interpolating the attribute across the face, which is precisely what the
varying vec2 v_texCoords in a modern shader is: a per-vertex value that arrives at the fragment shader already interpolated.