Answering my own question here, based partly on some hints given in the comments (thanks!), and partly figuring things out on my own...
The eventual route I took was to scrap my modifications to the Allegro source, and instead render the lightmap using shaders.
As a bit of background: I compute the lightmap for the entire world "offline" in a separate thread.
In the render loop, I take just the visible area of the lightmap (plus an extra tile all around) and draw that to an Allegro memory bitmap.
I can then provide that bitmap as a sampler to the shader that will draw the tiles.
The trick is to realise that you can take the special
al_pos vector from the vertex shader, that gives the screen position, transform it according to the offset and scale of the overall tile drawing and pass it through to the fragment shader, to be used as a texture coordinate of the lightmap sampler.
attribute vec4 al_pos;
attribute vec4 al_color;
attribute vec2 al_texcoord;
uniform mat4 al_projview_matrix;
uniform vec2 lightmap_scale;
uniform vec2 lightmap_offset;
out vec4 varying_color;
out vec2 varying_texcoord;
out vec2 varying_lightmap_texcoord;
varying_color = al_color;
varying_texcoord = al_texcoord;
varying_lightmap_texcoord = (al_pos.xy + lightmap_offset) / lightmap_scale;
gl_Position = al_projview_matrix * al_pos;
lightmap_scale are fed is as uniform
vec2s on each frame.
lightmap_offset ranges from 0 to the size of a tile. It is the
offset of the overall drawing, modulo tile size.
the size of the lightmap. It is the size of the lightmap times the
size of a tile.
Now the fragment shader:
uniform sampler2D al_tex;
uniform sampler2D lightmap_sampler;
in vec4 varying_color;
in vec2 varying_texcoord;
in vec2 varying_lightmap_texcoord;
vec4 texture_value = texture(al_tex, varying_texcoord);
vec4 lightmap_value = texture(lightmap_sampler, varying_lightmap_texcoord);
gl_FragColor = texture_value * lightmap_value;
This is very simple: just look up into the tile texture, and the lightmap sampler, and combine them.
Or to think about it another way: I stretch the lightmap over the entire window (and then some). The scale and offset calculations simply work out exactly how it is positioned.