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

[rshapes] DrawRectangleRoundedLines() results not aligned with DrawRectangleRounded() #4601

Open
Kaehvaman opened this issue Dec 14, 2024 · 10 comments

Comments

@Kaehvaman
Copy link

  • [*] I tested it on latest raylib version from master branch
  • [*] I checked there is no similar issue already reported
  • [*] I checked the documentation on the wiki
  • [*] My code has no errors or misuse of raylib

Issue description

DrawRectangleRoundedLines draws weird unequal corners and is taller and wider than DrawRectangleRounded, which draws identical corners.
DrawRectangleRoundedLinesEx with lineThick != 1 works as expected, so the issue is linked to lineThick of 1 pixel.

Environment

Windows 10
Visual Studio 2022
MSVC
C language
raylib.lib from v5.5 release
INFO: GL: OpenGL device information:
INFO: > Renderer: AMD Radeon RX 6750 XT
INFO: > Version: 3.3.0 Core Profile Context 24.10.1.241007
INFO: > GLSL: 4.60

Issue Screenshot

Screenshot_2

Code Example

Rectangle roundRect = { 100, 250, 185, 36 };
DrawRectangleRounded(roundRect, 0.5f, 6, BLACK);
DrawRectangleRoundedLines(roundRect, 0.5f, 6, ORANGE);

@raysan5 raysan5 changed the title [rshapes] DrawRectangleRoundedLines produces weird results [rshapes] DrawRectangleRoundedLines() results not aligned with DrawRectangleRounded() Dec 23, 2024
@raysan5
Copy link
Owner

raysan5 commented Dec 23, 2024

I think the issue is related to an off-by-one-pixel on lines calculations and I'm afraid that's a GPU-driver dependant issue, very difficult to address. Related to this, we have DrawRectangleLines() that still fails after many many changes and tries to solve the off-by-one-pixel issue...

@Kaehvaman
Copy link
Author

Wow, never expected a driver to break such a simple thing

@Kaehvaman
Copy link
Author

Updating to 24.12.1 driver didn't fix the issue :(

@Bigfoot71
Copy link
Contributor

Bigfoot71 commented Jan 7, 2025

@raysan5 I get exactly the same result, seemingly pixel-perfect, on:

INFO:     > Vendor:   NVIDIA Corporation
INFO:     > Renderer: NVIDIA GeForce GTX 980/PCIe/SSE2
INFO:     > Version:  3.3.0 NVIDIA 550.120
INFO:     > GLSL:     3.30 NVIDIA via Cg compiler

image

I tried enlarging and highlighting the offset with transparency if that helps:
image

However, if I use DrawRectangleLines, the one-pixel offset to the left and bottom doesn't appear.
Instead, there's an extra pixel on the bottom-right and top-right:
image

Edit:
Just a thought, depending on how lines are rasterized in this context, shouldn't we expect to specify the centers of the pixels? In other words, for an orthographic projection that aligns with the screen edges (0, w, 0, h), a position of (0, 0) would correspond to the outer edge of the screen, and we would need to specify the pixel center at (0.5, 0.5).

I haven't dug deeply to check if raylib applies this kind of correction, but the observed offset might come from this?

@raysan5
Copy link
Owner

raysan5 commented Jan 7, 2025

@Bigfoot71 There could be multiple elements involved in the pixel offsets and the rounded corners, from GPU to driver (specially on integrated GPUs). But definitely requires some review.

About DrawRectangleLines() it has been reviewed several times, latest recently for 5.5 release... but keeps failing... 😖

The 0.5 offset has been also tried several times and it's also platform dependant...

@Bigfoot71
Copy link
Contributor

I have potentially made a good assumption in my previous comment.

To begin with, the observed one-pixel offset with DrawRectangleLines actually comes from the use of zoomFactor, which is added or subtracted.

By removing these extra operations, I get the following:
image

So, we no longer have the extra two pixels, but we still have some strange offsets...

Then, I simply used c + 0.5 and c + s - 0.5 (where c represents x or y and s represents w or h), and we finally get what seems to be pixel-perfect results:
image

So, I tried exactly the same approach with DrawRectangleRoundedLines and it works!
image

Here the points:

    const Vector2 point[16] = {
        {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f}, 
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f}, 
        {rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius - 0.5f}, // PO, P1, P2
        {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius + 0.5f}, 
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4
        {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f}, 
        {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, 
        {rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7
        {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f}, 
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9
        {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius - 0.5f}, 
        {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius + 0.5f}, // P10, P11
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f}, 
        {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13
        {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius + 0.5f}, 
        {rec.x + 0.5f, (float)rec.y + innerRadius - 0.5f} // P14, P15
    };

    const Vector2 centers[4] = {
        {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f}, 
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17
        {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, 
        {(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19
    };

@Bigfoot71
Copy link
Contributor

The 0.5 offset has been also tried several times and it's also platform dependant...

@raysan5 Argh, I just did a test with the response right above using the 0.5 offset, but if it doesn't work everywhere, it's probably because different hardware/drivers have different rounding conventions.

In that case, it's a lost cause. We can do our best for the most common convention, but listing the conventions for each hardware/driver to adapt the method seems like a futile effort...

@raysan5
Copy link
Owner

raysan5 commented Jan 7, 2025

@Bigfoot71 Looks nice, does it work on NVIDIA and AMD? Feel free to send a PR and I'll try on my laptop with NVIDIA and Intel integrated graphics.

@Bigfoot71
Copy link
Contributor

Looks nice, does it work on NVIDIA and AMD? Feel free to send a PR and I'll try on my laptop with NVIDIA and Intel integrated graphics.

@raysan5 I just created a PR, draft for now, as I would like to get your feedback on DrawRectangleLines.

Otherwise, I was able to test this on an old laptop with an NVIDIA Quadro NVS 160M (no issues), that's all I can do from home.

It would be great if @Kaehvaman could try replacing the points I shared above in DrawRectangleRoundedLinesEx to see if everything looks good.

@Kaehvaman
Copy link
Author

It would be great if @Kaehvaman could try replacing the points I shared above in DrawRectangleRoundedLinesEx to see if everything looks good.

@Bigfoot71 I compiled your fork and it looks ok, except for some overlapping pixels (i used colors with 150 alpha).

Screenshot_7

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

No branches or pull requests

3 participants