Affine Texture Mapping

This requires the Basic 3D Software Rasterisation and Vertex Colouring first.

A texture is needed, it is sampled based on UV coordinates assigned to each vertex. A UV coordinate is in the range 0 to 1.

A simple way to sample is to use nerest neighbour

static Color sample_texture(const Color *texture, float u, float v)
{
    /* Clamp to [0,1] in case interpolation nudges slightly outside the
     * triangle's UV range due to floating point rounding. */
    if (u < 0.0f) u = 0.0f;
    if (u > 1.0f) u = 1.0f;
    if (v < 0.0f) v = 0.0f;
    if (v > 1.0f) v = 1.0f;
    int tex_x = (int)(u * (TEXTURE_SIZE - 1));
    int tex_y = (int)(v * (TEXTURE_SIZE - 1));
    return texture[tex_y * TEXTURE_SIZE + tex_x];
}

In the triangle rasterisation code once we have the three normalised barycentric weights we interpolate the UV coordinates instead of Vertex Colouring, and use the sample_texture function to get the relevant pixel colour. The rest is identical.

float u = w0 * uv0.x + w1 * uv1.x + w2 * uv2.x;
float v = w0 * uv0.y + w1 * uv1.y + w2 * uv2.y;
Color sampled = sample_texture(texture, u, v);
pixels[y * WINDOW_WIDTH + x] = sampled;