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.
Vertex shader:
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;
void main()
{
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_offset
and lightmap_scale
are fed is as uniform vec2
s 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.
lightmap_scale
is
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;
void main()
{
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.
Allegro
correctly interpolates that to the rest of the rectangle. Are you trying to do a "Fog of War" effect? \$\endgroup\$