Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scaling distortion #159

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

filippos-lagopoulos
Copy link

  • Added a pixel to the left and top of a glyph to get rid of distortion when scaling. I suspect this only needs to be used with glyphs that are adjacent to the edges of the texture but given that the packing algorithm here is pretty awesome, it doesn't look like this will have a major impact on the texture's size.
  • Moved the texture coordinates by the left&top padding and used the unpadded glyph size for the calculation of the coordinates. It seems to me that glyphs are stretched by one pixel on both axis if we use the padded size.

@rougier
Copy link
Owner

rougier commented Mar 26, 2017

What is the distortion you're referring to? Would you have some example before/after your fix (because it is not totally clear to me)?

@filippos-lagopoulos
Copy link
Author

filippos-lagopoulos commented Mar 26, 2017

distorted_scaled
clean_scaled
I've attached two images of some text rendered using the code and shaders from the sub-pixel example, in the first case without the changes in this branch and in the second with them. The program is using a camera which is positioned close to the text so its actually stretched/zoomed.

It seems odd to me that padding is taken into account when calculating the glyph's texture coordinates. I'm not sure if this is intentional to get smoother edges but it does result in a one pixel larger glyph both in width and height, since the calculation is:

glyph->width    = tgt_w;
glyph->height   = tgt_h;

Where tgt_w and tgt_h are:

size_t tgt_w = src_w + padding.left + padding.right;
size_t tgt_h = src_h + padding.top + padding.bottom;

And on master padding is:

struct {
    int left;
    int top;
    int right;
    int bottom;
} padding = { 0, 0, 1, 1 };

Which means the total size say for 20x30px glyph will be

size_t tgt_w = 20 + padding.left + padding.right = 20 + 0 + 1 = 21
size_t tgt_h = 30 + padding.top + padding.bottom = 30 + 0 + 1 = 31

Which means that if we use tgt_w and tgt_h we get:

glyph->width    = 21;
glyph->height   = 31;

Shouldn't the glyph size just be 20x30 no matter what the padding is?

Plus the left/top padding values are not taken into account which means that if we use a left/top padding the actual glyph will be positioned at (padding.left, padding.top) texels/pixels in front of the texture coordinates. That's what this bit fixes:

x += padding.left;
y += padding.top;

It might be that I totally misunderstand but it does seem odd. And I get these weird lines when scaling/zooming. The picture I've attached seems to have these lines right at the baseline but this is not always the case. I get them also around the edges. They all seem to go away if I use the actual glyph size (i.e. src_w,src_h) and use at least 1px for left/top padding and offset the uv's by it.

I think also in the case of a distance field (which is actually using a left/top padding of 1 on master) we still want to offset the positions by the left/top padding. Haven't tested this, but I was trying to use it in our application and was getting these weird lines now that I think about it. I might try it again probably in a few days.

@rougier
Copy link
Owner

rougier commented Mar 27, 2017

Thanks, I see the problem now but there is still problems with the fix you made I think. It's like some glyphs are cut at the bottom (maybe one pixel cut). I don't have much time right now to investigate but I will as soon as I can (unless you fix the remianing bug).

@filippos-lagopoulos
Copy link
Author

filippos-lagopoulos commented Mar 27, 2017

You're right I noticed that but thought the size must be right when using src_w and src_h. But the glyphs on master do have 1 additional pixel at the edge which makes them look smoother. I'll keep investigating.

@cmrschwarz
Copy link
Contributor

Very interesting work! I have had similar issues even when unscaled and would appreciate it very much to see this fixed. Unfortunately I also don't have the time to look into it right now.

@filippos-lagopoulos
Copy link
Author

filippos-lagopoulos commented Apr 3, 2017

Here is a hack to fix this. Although I would suggest to keep this PR open until we find a proper fix and the reason why this is happening. I will use this hack to make the text in our application look better but will not commit to this branch. Its dead easy though.
So instead of using the original glyph size (i.e. src_w and src_h) when calculating the texture coordinates we can use src_w + 1 and src_h + 1. So the code would look like this:

    float uvx = x + padding.left;
    float uvy = y + padding.top;
    float uvz = src_w+1;
    float uvw = src_h+1;

    glyph = texture_glyph_new( );
    glyph->codepoint = utf8_to_utf32( codepoint );
    glyph->width    = uvz;
    glyph->height   = uvw;
    glyph->rendermode = self->rendermode;
    glyph->outline_thickness = self->outline_thickness;
    glyph->offset_x = ft_glyph_left;
    glyph->offset_y = ft_glyph_top;
    glyph->s0       = uvx/(float)self->atlas->width;
    glyph->t0       = uvy/(float)self->atlas->height;
    glyph->s1       = (uvx + uvz)/(float)self->atlas->width;
    glyph->t1       = (uvy + uvw)/(float)self->atlas->height;

You can obviously skip this bit now (since uvx and uvy already contain the padding):

x += padding.left;
y += padding.top;

This will remove the scaling distortion and it will add the missing pixel that exists on master and not on this branch. You also get cleaner rotated text using this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants