So, if I use content scaling I will always have that problem?
It’s caused by “fractional” content scaling/coordinates. The position and width of your lines in content coordinates (ie: in OpenGL coordinates) are fractional, but when rendered, the video hardware picks the closest pixel it’ll be rendered to (ie: pixel coordinates which are whole numbers). So, for example, if you set the line thickness to 1 in content coordinates which calculates to be 1.5 pixels wide, the video hardware will either render it 1 or 2 pixels wide? Which will the video hardware decide to pick? You have no way of knowing. Especially if the position of the line lands on fractional coordinate too.
Note that this isn’t a Corona issue. This is something that all OpenGL/Direct3D developers have to deal with. Particularly with UI rendering where perfect pixel positioning/sizing is expected, because this really isn’t an issue when rendering a scene in say a game world.
So, if you want perfect pixel widths for your rectangles, then you’ll need to calculate a line width in content coordinates that rounds up to the next whole number in pixels. Perhaps something like this…
-- The line width you want in content coordinates. local lineWidth = 2 -- Round up the line width to the nearest whole number pixel. lineWidth = math.ceil(lineWidth / display.contentScaleY) \* display.contentScaleX
And here’s a “main.lua” I slapped together that you can test with. This drawing 10 horizontal lines on a white background.
local background = display.newRect(display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight) background:setFillColor(1, 1, 1) local lineCount = 10 for index = 1, lineCount do local y = (display.contentHeight / lineCount) \* index local line = display.newLine(0, y, display.contentWidth, y) line:setStrokeColor(1, 0, 0) local lineWidth = 3 lineWidth = math.ceil(lineWidth / display.contentScaleY) \* display.contentScaleY line.strokeWidth = lineWidth end
The above should produce consistent line width… except when you zoom in/out in the Corona Simulator. The reason it doesn’t work with a zoomed in/out simulator is because the display.contentScaleX/Y no longer matches when they’ll really be onscreen in pixels because there is an additional simulator scaling being applied. But on device, this should be fine.
Hi Joshua,
Trying this. Saw it in another post of yours. Not working yet.
–Scot
Here is the function I’m using:
local lineWidth = function (width) local width = width width = math.ceil(width / display.contentScaleY) \* display.contentScaleY return width end
Here is the screenshot from the device:
Well can’t seem to upload a screenshot, but it looks similar to the one above.
I don’t think the proposed fix can work. The width must be changed based on the Y position, because only when the Y position is fraction that the width must be adjusted properly.
In our case we have been dealing with this bug forever in the tableview. As the separator line is never the same height depending on the device. It looks very bad on some devices. We also try using newRect instead of new line, but same result.
It definitely works. The idea is that the width needs to be a whole number in *pixels*, not in scaled *content coordinates*. Corona’s content coordinates that you use for positioning and sizing objects are scaled and will translate to fractional pixel coordinates.
It’s not technically a bug. The problem is that you can’t actually display a line width less than 1 pixel on a screen (as in the physical pixel on the screen), unless you get lucky and the video driver happens to round it up on you. If you think about this problem in physical pixels, then what I’m saying makes a lot of sense.
For UI, you really want to render your content in pixels. That means reversing Corona’s content scaling to pixels.
For content, such as games and other scaled visuals like photos, it’s okay for pixels to be scaled out because it isn’t noticeable.
@Joshua, my bad, I did not see your statement about the simulator. I have try it directly on our android device and it is working. Thanks, we now have nice separator
I am owing Joshua an apology because I was not able to test his solution yet (super busy with a new project).
Thanks @nmichaud for already trying it and letting us know that it works!.
nmichaud, glad you got it working! Yeah, if the Corona Simulator is scaled, then you have no means of converting back to pixels unfortunately because the display.contentScale* property is constant, meaning it doesn’t change when you scale the simulator. But, a situation like that would never happen on a real device so its a design flaw we felt we can live with. Just a little confusing if you’re going for pixel perfect position. Sorry about that.
Renato, no worries. We no you’re a busy guy. But hey, nmichaud did you a service and proved that it works on his end.