I have a much-larger-than-the-screen map, on which is being tiled many layers of individually scaled textures. So for one of these scaled textures, it looks a little like the below (where the textures are actually drawn next to each other in the map, but that looks odd in ascii
┌──────────────────────────┐
│ │
│ │
│ Map-sized mask │─┐
│ │ │
│ │ │
└──────────────────────────┘ │
│
│ ┌──────────────────────────┐
┌───────────┐ Scaled │ │┌ ─ ─ ┌ ─ ─ ┌ ─ ─ │
│ │ Texture │ │ │ │ │ │
│Texture at │ ┌────┐ │ ││ │ │ │
│ full size │ ────▶ │ │ ──┴─▶ │ ─ ─ ┘ ─ ─ ┘ ─ ─ ┘ │
│ │ │ │ │ Map │
└───────────┘ └────┘ └──────────────────────────┘
So I was reading up on how shaders work, since they're new to me. It seems I need two sets of co-ordinate space (one for the global mask, one for the scaled-down texture), so I'm passing in enough uniforms to work that out.
The shader code looks like:
uniform sampler2D texture; // Scaled-down texture to tile over the map
uniform sampler2D mask; // Map-sized global mask
uniform float maskX; // x pixel of where to pull the mask data from
uniform float maskY; // y pixel of where to pull the mask data from
uniform float maskW; // total mask width in pixels
uniform float maskH; // total mask height in pixels
uniform float scaledW; // width of the scaled-down texture in pixels
uniform float scaledH; // height of the scaled-down texture in pixels
void main()
{
// lookup the pixel in the mask texture
float mx = maskX / maskW + gl_TexCoord[0].x * scaledW / maskW;
float my = maskY / maskH + gl_TexCoord[0].y * scaledH / maskH;
vec4 maskPixel = texture2D(mask, vec2(mx, my));
// lookup the pixel in the drawing texture
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
// set it to scaled:rgb, mask:alpha
gl_FragColor = vec4(pixel.rgb, maskPixel.a);
}
.. and the drawing code looks like:
sf::Sprite scaledSprite;
scaledSprite.setTexture(_scaled->getTexture());
int x = 0;
int y = 0;
int w = scaledW;
int h = scaledH;
while (y < maskH)
{
h = (y + scaledH > maskH) ? maskH - y : scaledH;
while (x < maskW)
{
w = (x + scaledW > maskW) ? maskW - x : scaledH;
scaledSprite.setPosition(x, y);
sf::Shader *shader = [[Shaders sharedInstance] paintWithMaskShader];
shader->setUniform("texture", sf::Shader::CurrentTexture);
shader->setUniform("mask", _mask->getTexture());
shader->setUniform("maskX", x);
shader->setUniform("maskY", y);
shader->setUniform("maskW", maskW);
shader->setUniform("maskH", maskH);
shader->setUniform("scaledW", scaledW);
shader->setUniform("scaledH", scaledH);
_result->draw(scaledSprite, shader);
x += w;
}
x = 0;
y += h;
}
So basically just iterating over the map-sized RenderTexture '_result', using the shader to tile the scaled-down version of a texture, modulated by the corresponding area in the map-sized mask. the problem is that I'm not seeing the alpha value (supposed to come from the mask) work correctly, it's always the same value across the image.
I created a mask texture by calling clear(0,0,0,64) and then drawing a filled circle at (70,70) with colour (255,255,255,255). If I dump that texture to a file, it looks totally reasonable (see attached, scaled down) so when I apply it, I'd expect a circle of the drawn texture to be brighter than the surrounds, but they're all being set to alpha 0.25 (and if I change the (0,0,0,64) color to (0,0,0,128) it's drawn at intensity 0.5)
So, the shader is providing data, the texture is there, but it's not mapping in the correct alpha co-ordinates. I thought the texture co-ords were supposed to range from 0...1, so the calculation for the mask co-ords (based on the scaled-down texture being drawn) is:
- Figure out the offset in the global map (mx = maskX / maskW) in 0...1 co-ords
- Take the fraction across the scaled image, and multiply by the ratio (scaledWidth / maskWidth)
- Add them together
The idea was to get 0...1 co-ords in the mask texture, but clearly I'm not doing that. Does anyone have any idea what I'm doing wrong ?