1
\$\begingroup\$

I'm in the very early stages of writing a 2d tile-based game using Allegro. I've hacked the Allegro source to allow me to specify tint values at each corner of a bitmap, however the resulting image has very obvious patterning where the quad for the bitmap has been rendered as two triangles:

Tiles showing diagonal pattern

As you can see, there are clear diagonal patterns going from top-left to bottom-right of each quad.

I'm not really sure of the correct terms to be able to search for a solution...

Are there any techniques I can apply to avoid these sorts of artifacts?

Thanks!

UPDATE: To show an example, here is the lighting system with all corners red, except for the bottom-left green:

Bottom-left green

And now, here's the equivalent with all corners red apart from the bottom-right green:

Bottom-right green

You can see the patterning is very different - not simply a 90 degree rotation.

Here's some of the Allegro code I modified: https://github.com/stu-smith/allegro5/blob/al_draw_corner_tinted_scaled_bitmap/src/win/d3d_bmp.cpp#L187

\$\endgroup\$
11
  • \$\begingroup\$ To me it looks like you've changed the colour of only one corner, and it renders as it should. Have you changed the tint on multiple corners? If there is a rectangle with 3 black corners, and one white, the pixels in the middle will be mostly black, because they are affected by 3 corners, versus the 1 white. You can observe a similar result if you open a 3D modeling software, create rectangle and apply 3 black corners and 1 white using vertex colours. This is not the result of the bitmap being rendered as 2 triangles, you can confirm that by painting 2 corners instead of only 1. \$\endgroup\$ – TomTsagk Feb 7 '20 at 16:05
  • \$\begingroup\$ I think I've got things correct, and I've updated the question with some examples of lighting being overridden. \$\endgroup\$ – stusmith Feb 7 '20 at 16:15
  • \$\begingroup\$ I have found this: gamedev.stackexchange.com/questions/126078/… ... which is a completely different approach. I may have to go down that route if there is no solution to the way I've tried things. \$\endgroup\$ – stusmith Feb 7 '20 at 16:15
  • \$\begingroup\$ I'm not saying you did something wrong, I'm saying the results you expect will not happen with this method. This has nothing to do with shapes being rendered as triangles or rectangles. You've painted one corner with a colour, and Allegro correctly interpolates that to the rest of the rectangle. Are you trying to do a "Fog of War" effect? \$\endgroup\$ – TomTsagk Feb 7 '20 at 16:18
  • 1
    \$\begingroup\$ You may want to show us how you are applying this tint. Depending on where it's being injected into the shading logic, there may be opportunities to control the interpolation to have a different look. \$\endgroup\$ – DMGregory Feb 7 '20 at 16:21
0
\$\begingroup\$

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 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.
  • 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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.