SFML community forums
Help => Graphics => Topic started by: Megatron on November 03, 2010, 07:28:33 am
-
I was wondering if it's possible to draw a text object so that the font has an outline?
for instance, if I have a white font, I may want to put a thin black border around it to accentuate it. I'd assume it'd be possible via shaders, but I was wondering if there was a way that doesnt rely on shaders.
I'm using the .net bindings for SFML so that may be a possible limitation.
If anyone has an idea how to do this that they could share, that'd be great.
Thanks
-
Well, you could try wrapping two strings inside your own string class.
Make one string slightly larger then the other, and place it behind the smaller one to give an 'outline' effect.
-
No, this is not possible at all sorry.
Make one string slightly larger then the other, and place it behind the smaller one to give an 'outline' effect.
This will not produce the desired effect ;)
-
I personally do this right now by drawing the text 5 times. Draw the background using the offsets of (0,1),(1,0),(0,-1),(-1,0) (up,down,left,right) and then the normal text. Inefficient? You betcha! But it gets the job done.
I have looked into doing this with shaders, but I couldn't find any decent way of doing it without some of the features of newer version of GLSL (namely the ability to look up the size of the texture so you could actually use a pixel scale).
-
namely the ability to look up the size of the texture so you could actually use a pixel scale
If that's the only thing you need, you can send it manually to the shader through a variable.
-
namely the ability to look up the size of the texture so you could actually use a pixel scale
If that's the only thing you need, you can send it manually to the shader through a variable.
That was what I had in mind at first, too, but didn't realize at the time that Font had a GetImage method (clearly I didn't look very hard). Maybe I'll play around with it again and see if I can whip up something.
-
Wouldn't a font like that work? http://www.dafont.com/bower-shadow.font
-
It works as long as you don't want to control the outline width or color.
-
The problem with doing it inside of a font file directly, or applying it to a font using SetPixel, is that you are increasing the amount of memory used to store your fonts. With using a font with outlines built-in, it also introduces a lot more hassle.
Ideally, you want to be able to just say "use outline", and it draws with outlines with no reduction to performance and takes up no extra memory. With shaders, this is likely possible since not many of us are going to be bottlenecked on the fragment processing (unless you are already using some heavy shaders).
-
Well, after a few hours, I managed to come up with something that works decently. Took quite some time to come up with the right algorithm to preserve the alpha values properly.
uniform sampler2D tex;
uniform vec2 texSize;
uniform vec4 outlineColor;
void main(void)
{
vec2 off = 1.0 / texSize;
vec2 tc = gl_TexCoord[0].st;
vec4 c = texture2D(tex, tc);
vec4 n = texture2D(tex, vec2(tc.x, tc.y - off.y));
vec4 e = texture2D(tex, vec2(tc.x + off.x, tc.y));
vec4 s = texture2D(tex, vec2(tc.x, tc.y + off.y));
vec4 w = texture2D(tex, vec2(tc.x - off.x, tc.y));
vec4 origColor = c * gl_Color;
float ua = 0.0;
ua = mix(ua, 1.0, c.a);
ua = mix(ua, 1.0, n.a);
ua = mix(ua, 1.0, e.a);
ua = mix(ua, 1.0, s.a);
ua = mix(ua, 1.0, w.a);
vec4 underColor = outlineColor * vec4(ua);
gl_FragColor = underColor;
gl_FragColor = mix(gl_FragColor, origColor, origColor.a);
if (gl_FragColor.a > 0.0)
gl_FragColor.a = 1.0;
}
There is a little issue with the display of the first character. It seems SFML adds a little white block to the top-left corner of a font bitmap, so that ends up making a little artifact display for the first character. In theory, it'll also show artifacts if there are any font characters without padding between them in the font texture. Could get rid of this by just clamping the texture coordinates, but don't know of any way of finding the specified coordinates for the draw call without passing them as a parameter (which would require modifying SFML to update that parameter before each character is drawn).
Edit: Updated the shader. Kinda disappointed in myself for not realizing to take this approach initially. Was too stuck on the idea of recognizing when the edge has been reached.
-
Thanks spodi, the way you mentioned before worked, Ill give the shader a try later