1. Anders Ruud
  2. love
  3. Issues

Issues

Issue #595 wontfix

Inconsistent rectangle drawing among OSes

hryx
created an issue

This may be related to issue #365 but I'm creating a new one in case it isn't.

At scale=1, drawing a 'line' mode rectangle works as expected. In 'fill' mode, the offset is different per OS.

In Linux:

  • x is off by +1
  • height is off by -1
  • upper and right bounds are placed correctly

In OS X:

  • x is off by +1
  • y is off by +1
  • lower and right bounds are placed correctly

The exact offsets are slightly different when scaled. Please see the attached .love and try on various OSes.

I haven't tested Windows. The attached .love does not test fonts or images, so I dunno if they're affected.

Is this a problem with OpenGL or graphics cards, or with LOVE? I'll be happy to report my hardware if relevant.

Comments (7)

  1. Boolsheet

    Wait, fill mode is different for you? Are you sure about that? Can you upload images of the two?

    Note that when you call love.graphics.line(0, 5, 800, 5), LÖVE will put the line between the fifth and sixth pixel row (assuming default settings and rough mode). I don't know if the OpenGL specification says something about the case where the edge lands directly on the sample point. Clearly, different implementations resolve this differently or maybe it's because the value gets processed in a way that changes the outcome (floating-point numbers and all that fun). Turn on FSAA and you'll see that both rows get some of the color.

    Same thing applies to line mode for the other primitives as they use the same line drawing function internally.

    Try if this code still produces differences. It will create a screenshot if you press F5.

    -- Off-by-1 test
    love.filesystem.setIdentity("pxtest")
    local mode = 'fill'
    local scale = 1
    
    function love.keypressed(key, code)
        if key == ' ' then
            mode = mode == 'fill' and 'line' or 'fill'
        elseif key == '1' or key == '2' or key == '3' or key == '4' or key == '5' then
            scale = tonumber(key)
        elseif key == "f5" then
            screenshot = true
        end
    end
    
    love.graphics.setLine(1, 'rough')
    function love.draw()
        love.graphics.setColor(0xff,0xff,0xff)
        love.graphics.print('Space: toggle\n1-5  : scale', 200, 4)
        love.graphics.scale(scale)
    
        love.graphics.setColor(0xff,0,0)
        if mode == "line" then
            love.graphics.rectangle(mode, 10.5, 10.5, 39, 39)
        else
            love.graphics.rectangle(mode, 10, 10, 40, 40)
        end
    
        love.graphics.setColor(0,0xff,0)
        love.graphics.line(9.5, 9.5, 30.5, 9.5)
        love.graphics.line(9.5, 9.5, 9.5, 30.5)
    
        love.graphics.setColor(0xff,0xff,0)
        love.graphics.line(50.5, 50.5, 50.5, 29.5)
        love.graphics.line(50.5, 50.5, 29.5, 50.5)
    
        if screenshot then
            screenshot = nil
            love.graphics.newScreenshot():encode("img"..scale..".png")
        end
    end
    
  2. Boolsheet

    It means you have to be aware that you specify the middle points of the line when you call love.graphics.line or love.graphics.rectangle("line", ...) and that the center of a pixel is at x + 0.5 if the coordinate system hasn't been transformed.

  3. hryx reporter

    But does that explain the different behavior on different systems? I bring this up because it is visually noticeable in my current project.

  4. hryx reporter

    Hi there. Sorry to bump, but I'm wondering what I should do to make my project consistent among operating systems.

    1. Change my code behavior and draw lines offset by 0.5px?
    2. Wait for an update to LOVE (if this is even something it can fix)?

    Thanks! And you can ignore my last comment; I reread your explanation.

  5. Boolsheet

    I don't know your project so I can't tell you anything specific about that.

    What I can tell you is that if you want a line to be exactly on a pixel row, it's necessary to offset it by 0.5 to get it on there (assuming the coordinate system hasn't been transformed). I talk a bit about the reasons over here.

    If the different behavior comes from the OpenGL implementations or floating-point rounding, I doubt LÖVE can do anything about it. It's an edge case (literally, heh) that can fall on both sides.

  6. Log in to comment