Draw text outline with Freetype - c++

I've implemented FreeType in my program, I can draw text with colors and style (Bold, Italic, Underline).
Now I would like to make an outline effect on my text. How can I do it?
(source: googlecode.com)
I've tried to draw the text two times, one larger in black in background and the second in white on foreground, result was wrong.
I've tried to draw the text two time, one in bold and the second in one on foreground, here again the result was wrong.
I would like to make a test again : Draw the "background" text in "outline" mode and the foreground text in regular mode. What do you think about it?
(source: googlecode.com)

Rendering text with 2 passes is the key, but you have to position the text correctly.
First you should render whole outline and then on top of it render the text.
Rendering the outline:
// initialize stroker, so you can create outline font
FT_Stroker stroker;
FT_Stroker_New(library, &stroker);
// 2 * 64 result in 2px outline
FT_Stroker_Set(stroker, 2 * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
...
// generation of an outline for single glyph:
FT_UInt glyphIndex = FT_Get_Char_Index(face, glyphId);
FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
FT_Glyph glyph;
FT_Get_Glyph(face->glyph, &glyph);
FT_Glyph_StrokeBorder(&glyph, stroker, false, true);
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, true);
FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
// blit the glyph here on your target surface.
// For positioning use bitmapGlyph->left, bitmapGlyph->top
// For iteration over the glyph data use bitmapGlyph->bitmap.buffer, bitmapGlyph->bitmap.width, bitmapGlyph->bitmap.rows, bitmapGlyph->bitmap.pitch.
Next you have to render the text itself on the same data you've blitted the outline. Use the code above, but remove the FT_Glyph_StrokeBorder(&glyph, stroker, false, true); line.
This way you will have the text on top of an outline.
To achieve this "Cartoon" text effect you will have to do 4 passes: 3 outlines + 1 text. Texturing or applying a gradient should be done during the blitting phase.

Draw the text, then do a second pass over every pixel that was not fully coloured in. For each of those pixels calculate how far away it is from the nearest coloured pixel. If it's less than X where X is the desired width of your outline, colour it in using your outline colour.
It can be slow to do this for large text but it can be optimised and the results cached to make it run acceptably fast. This method allows complete freedom for all kinds of outline and drop shadow effects.

Related

OpenGL - Set frame buffer texture to fully transparent

I'm trying to render some text, but at the moment I'm rendering each glyph separately, which is slow and ineffective.
Therefore I want to change the system, so the text is just rendered into a separate texture once, whenever it changes, and then that texture should be rendered onscreen in the main render pass.
So far so good, the problem is, to draw it over the main scene, I only have two options. I could specify a specific color (e.g. green) as 'transparent', clear the frame buffer texture of the text with that color, draw the text and use a shader afterwards to render the result onto the main scene, minus the transparent color.
While that would work, I wouldn't be able to use that color for the actual text anymore.
Instead I'd much rather clear the alpha of the frame buffer texture entirely (to get a colorless, blank slate essentially) and then draw the text, but that doesn't seem to be possible?
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_TRUE);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
Doing this will just apply the specified rgb values with the alpha as 'intensity' of those colors. In this case it wouldn't do anything at all because the color components are disabled. But I need to change the existing alpha of the texture in the frame buffer, without using glDrawPixels (which is too slow).
Now, I could of course write an additional shader to set the alpha-value for each fragment to 0, but that doesn't seem as effective / fast.
What's the best way to handle something like this?
So far so good, the problem is, to draw it over the main scene, I only have two options. I could specify a specific color (e.g. green) as 'transparent', clear the frame buffer texture of the text with that color, draw the text and use a shader afterwards to render the result onto the main scene, minus the transparent color.
You're overcomplicating the whole thing. If you render your text/glyphs into a texture that has just a single channel that's being used as alpha channel, that gives you the glphys shape. The color is controlled in form of a vertex attribute and combined with the alpha from the texture upon rendering.
If you want to get fancy, instead of rendering the bare glyphs to the texture, you might instead want to produce a signed distance field map, to save on texture size, while retaining high quality text output.

How to set a "plain" or "flat" background color for a QTableWidgetItem

I have a QTableWidget. I want to have alternating background colors for the rows, but I can't use QTableWidget::setAlternatingRowColors because I need one color for two rows and the other one for the next two and so on (see the below image).
Thus, when I add a QTableWidgetItem, I set the according background color manually by QTableWidgetItem::setBackground().
But I don't get a "flat" or "plain" background by this, but a gradient and rounded corners:
I would like to have the background color all over the cells, without further "decoration". How can I get rid of this?
When you select a single color as the background (QBrush constructed from a QColor), the style engine tries to render a styled background, which in your case draws this gradient with border.
You can trick the style engine by using a QBrush constructed from a QImage, so the render engine draws exactly that image and nothing more. In your case, use an image with a single pixel, namely the color you want as the background. For this, construct a 1x1-sized QImage and set the color of the pixel using fill, then use that image as a brush:
// Create the image (using the default image format)
QImage img(QSize(1, 1), QImage::Format_ARGB32_Premultiplied);
// Set the color, here light gray:
img.fill(QColor(224, 224, 224));
// Apply the image as the background for the item:
item->setBackground(QBrush(img));

TTF_RenderTextSolid() returns a Surface with 1 byte per pixel?

This code:
TTF_Font * titania = TTF_OpenFont( "chintzy.ttf",28);
SDL_Color textColor = {255,255,0};
SDL_Surface * textSurface = TTF_RenderText_Solid(titania,"Its Working!",textColor);
std::cout << (int)textSurface->format->BytesPerPixel;
Prints the number one, meaning that the surface returned by TTF_RenderTextSolid has one byte per pixel. If I am correct it should be 4 bytes per pixel. Does anyone know why this is happening?
Looks like it's doing exactly what the documentation says it ought to:
Solid
Create an 8-bit palettized surface and render the given text at fast quality with the given font and color. The pixel value of 0 is the colorkey, giving a transparent background when blitted. Pixel and colormap value 1 is set to the text foreground color. This allows you to change the color without having to render the text again. Palette index 0 is of course not drawn when blitted to another surface, since it is the colorkey, and thus transparent, though its actual color is 255 minus each of the RGB components of the foreground color. This is the fastest rendering speed of all the rendering modes. This results in no box around the text, but the text is not as smooth. The resulting surface should blit faster than the Blended one. Use this mode for FPS and other fast changing updating text displays.
If you want 32bpp you need to use the *_Blended() variants:
Blended
Create a 32-bit ARGB surface and render the given text at high quality, using alpha blending to dither the font with the given color. This results in a surface with alpha transparency, so you don't have a solid colored box around the text. The text is antialiased. This will render slower than Solid, but in about the same time as Shaded mode. The resulting surface will blit slower than if you had used Solid or Shaded. Use this when you want high quality, and the text isn't changing too fast.
Self Answer:
TTF_RenderTextSolid() returns a surface in false color. This means that it is kind of like black and white but white is a color you have defined and black is just the opposite of that color (which is usually completely transparent). It can be changed into a regular surface by using SDL_ConvertSurface.

Drawing text with shadow in OpenGL + FTGL

I'm drawing text in OpenGL using FTGL library and everything works just fine, however I would like to add shadow to the text. What I tried is drawing same text with black color and then draw text above that with normal color like this (pseudocode):
glColor3f(0, 0, 0); // outline color
DrawText(x-1, y-1, str);
DrawText(x+1, y-1, str);
DrawText(x+1, y+1, str);
DrawText(x-1, y+1, str);
glColor3f(1, 1, 1); // primary color
DrawText(x,y,str);
But I have to draw the text 5 times and it still does not look very good.
I would like to get something like on the screenshot
There are probably a lot of ways to achieve that - some with higher quality than others.
Here's what I would do:
render the text to an in-memory grayscale pixmap.
perform a gaussian blur on it (probably using a fast library such as QImageBlitz or ImageMagick). The blur radius should be about 2-3px.
apply a steep tone-curve to the blurred image, so the luminance range [0.0, 0.9] is mapped to nearly 0.0. This makes it stop being blurry, and the result is a "fattened" version of the text. The tone curve should look something like this:
render that as the shadow, in black (using an appropriate blending mode to emulate alpha-blending). Then render the regular yellow text on top of it (with a small offset of your choice).
Also, you can use different tone-curves depending on how soft a shadow you want. A linear tone-curve would give a very soft shadow.
I am usually doing it this way:
set color to semitransparent black, eg (0,0,0,0.5)
draw the text in all the nine directions (move to sides, and then diagonally)
draw the fg text.
It looks quite good, and you can speed it up with render list and translations.
see here: http://i.stack.imgur.com/Dh68y.png

BlendFunc for textured fonts with changing background

I am attempting to use Textured fonts as so that I can display text in my openGL scene. However I am having trouble finding glBlendFunc values that will work.
The background that the text will be placed on is a grayscale image but will change throughout the execution. Because the background changes the text could possibly be on top of any color from black to white.
The best values I have found are glBlendFunc(Gl.GL_SRC_COLOR, Gl.GL_ONE_MINUS_SRC_ALPHA). This will make the black box surrounding the character disappear but the character itself will fade as the background goes towards white.
Please help!
Do you want the text to invert based on the background color? white text over black background, black text on white? I think you can achieve an invert via blendfunc.
Alternatively you can use a font texture which has a "border" built into it to help set the character apart from the background. Imagine a white font w/ a smooth alpha blended black "glow". The font will look good against almost all colors.