Bug 466 : P3D smooshes the top row of pixels when drawing text or images
Last modified: 2010-01-21 08:50




Status:
ASSIGNED
Resolution:
-
Priority:
P3
Severity:
normal

 

Reporter:
fry
Assigned To:
fry

Attachment Type Created Size Actions
P2D vs. P3D Fonts image/png 2008-04-16 20:17 42.64 KB
Modified PFont.java - adds padding to generated fonts text/plain 2008-06-10 17:50 32.56 KB
Updated PFont.java that works against existing codebase text/plain 2010-01-21 08:50 22.33 KB

Description:   Opened: 2006-12-08 14:17
probably a rounding error for how pixels are grabbed from images.
Additional Comment #1 From fry 2007-01-19 08:17
*** Bug 487 has been marked as a duplicate of this bug. ***
Additional Comment #2 From ewjordan 2007-06-10 22:41
Just a thought: one thing that I know is that an (int) cast always rounds
towards zero, e.g. everything from -.999 to .999 will be cast to zero.
This could mean that if the rasterization casts are performed using (int)
instead of floor(), something that "should" be rasterized to y value -1 and
thus be invisible will, in fact, show up as 0. I'm not sure where this is
happening, but I do seem to remember from the core source that most casts
are done through int casts, not floor calls.
Additional Comment #3 From fry 2007-06-14 14:05
interesting, have you had a chance to try it with floor?
Additional Comment #4 From ewjordan 2007-06-15 06:57
Yeah, actually, I took a look through - found quite a few (int) casts where
the argument could possibly be negative, and though most of them are
innocuous some of them might not be (I've found at least one spot in PLine
where this bug would show up if not for a clipping bug that is hiding it; I
guess sometimes two wrongs do make a right). I don't really know if it's
worth the slight performance hit to change them all over to floor calls.
At the very least I don't think we should use the current implementation of
floor, as it's fairly slow (faster to just (int) and then subtract one if
the original number is negative). Probably the best bet is to leave them
unless they cause actual trouble.

Ultimately, though, I think the issue with this bug, if I understand it
(not entirely sure since there's no example and the one in bug 487 doesn't
seem to cause any problem for me - from what I gather, the problem is that
the top and left rows/cols of a texture are not drawn), is more that the
texture mapping is a bit off than that the pixel casts are wrong. I played
around with the way this was done, and with bilinear filtering off, I was
able to get pixel-perfect image() calls in P3D. Alas, with the filtering
on, I've not been very lucky so far, and to my knowledge the interpolation
is always on these days...

I think it's a matter (like so many other P3D bugs) of dealing with
sub-pixel precision and making sure that the mapped coordinates end up in
the right places - which means a lot of playing around with whether to add
.5, .01, EPSILON, or some other offset to a coordinate before you use it.
Probably something I can figure out eventually, but at the moment it's not
happening right. There might be some dependencies on the various 2D-in-P3D
bugs, too, though this bug is actually legit in 3D as well, from what I can
tell. Probably of minor significance, though, as it's just a couple rows
of pixels in the image getting eaten...if I figure it out, I'll let you know.
Additional Comment #5 From fry 2007-11-28 06:03
*** Bug 693 has been marked as a duplicate of this bug. ***
Additional Comment #6 From fry 2007-11-28 06:05
the main workaround for this issue:

1) if you only need flat text, use textMode(SCREEN). this will draw pixel
accurate text in screen space. it's also faster than the other text options.

2) if you're doing 3D text, use a larger font than the output size (e.g. if
the output is a 16px square, use ~30-40 px font). using
hint(ENABLE_ACCURATE_TEXTURES) may also help.
Additional Comment #7 From dch 2008-04-16 20:17
edit]
P2D vs. P3D Fonts

Hi Ben, Wondering if you could explain the size workaround mentioned at
bottom... I've tried hint(ENABLE_ACCURATE_TEXTURES) with no change, also
selecting a bigger font and reducing its size w' textFont() - (guessing this is
not what you meant). Or maybe I'm experiencing a different issue (see
attached)?
thanks much,
-dch
Additional Comment #8 From ewjordan 2008-06-10 17:44
Good news and bad news.

Good news first: I think I've cracked this one for text. As I suggested
before, the problem is partially the bilinear filtering, which is biased.
By which I mean that it only draws the "raw" image pixels if the
coordinates are exactly at the upper left edge of the pixel. This means
that for the first row and column of an image, unless the coordinate is
EXACTLY at the upper left edge, we are blending with the next row or
column. This is a problem because we would prefer to sometimes have the
first displayed row blended with the PREVIOUS row; unfortunately, since
there is no previous row, this never happens, so we have apparent clipping.

The solution is to simply add a tiny empty border around the font during
creation. 2 pixels seems to do it for me, producing text that actually
looks better in MODEL mode than SCREEN (yay!).

The bad news: this file only fixes fonts created with createFont(), not
.vlw files loaded from the data folder. This is not terrible, as any new
fonts created will be created with this fix in place, but "stale" .vlws
will need to be recreated.

This, I think, is as good as we can do for now, without totally changing
the way the bilinear filtering is done. I'll attach a modified PFont.java
so you can test this.
Additional Comment #9 From ewjordan 2008-06-10 17:50
edit]
Modified PFont.java - adds padding to generated fonts

Test code to see the results, make sure to compare with a recent release
version of P5 to see the difference:

PFont fontA;

void setup() {
size(640, 480, P3D);
background(255);
fontA = createFont("Serif", 24);
//fontA = loadFont( /* make a font and load it here */ );
textFont(fontA, 24);
textAlign(CENTER);
}

void draw() {
background(255);
fill(0);
String stringToPrint = "";
if (mousePressed) {
textMode(SCREEN);
stringToPrint = "Testing\nscreen mode\ntext";
} else {
textMode(MODEL);
stringToPrint = "Testing\nmodel mode\ntext";
}
text(stringToPrint, width*.5f+(mouseX-width*.5f)*.1f,
height*.5f+(mouseY-height*.5f)*.1f);
}
Additional Comment #10 From fry 2008-06-11 05:48
*** Bug 611 has been marked as a duplicate of this bug. ***
Additional Comment #11 From fry 2008-06-11 07:37
eric, i thought i'd emailed you about it separately but i can't find a note
of it... but did you find out anything about the regression? reported to
have occurred between 0123 and 0135 (probably in the 0124/0125 graphics
changes).
http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1205171649
Additional Comment #12 From ewjordan 2008-06-11 19:53
> eric, i thought i'd emailed you about it separately but i can't
find a note
> of it... but did you find out anything about the regression? reported to
> have occurred between 0123 and 0135 (probably in the 0124/0125 graphics
> changes).

Yeah, two things happened between 0123 and 0125 relevant to this, as far as
I can tell, each partially responsible - first, bilinear filtering was
turned on by default for all texturing, and second, bug 95 was resolved
with a small shifting when things were drawn untransformed to the screen
plane. The first made text a little blurrier, and clipped a bit off the
top and left (bilinear filtering handles edge pixels a little bit worse
than trivial filtering), and the second shifted it to where the bias looks
particularly bad. Rolling either of those back is not a great idea,
because the bilinear filtering actually looks great except at the top/left
edges, and the shift is necessary to get shape drawing to be at the right
positions when integers are passed. Hence the hack of adding a border to
the generated font, which seems to make things look good again.

In other words, the underlying problem was always there (and still is, for
that matter), and is that we're using a biased texture filter that will
never fully draw the uppermost or leftmost pixels of a texture. It could
take a decent bit of work to fix that, though it's not impossible (you just
need to shift the bilinear mixing so that it's centered). The regression
was just a matter of those two other fixes exposing the problem a little
more fully.
Additional Comment #13 From fry 2008-06-25 13:53
ah, of course. thanks again for checking into this.. it's enormously helpful.
Additional Comment #14 From wanegain 2009-03-01 17:16
can someone post an attachment with the PFont.class instead of java ? I
have a hard time compiling it... thanks
Additional Comment #15 From msilva 2010-01-21 08:50
edit]
Updated PFont.java that works against existing codebase

Here's an updated PFont.java that applies the 2 pixel padding fix.