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

Drawing Bezier curves #32

Open
GrahamJoonsar opened this issue Feb 27, 2022 · 7 comments
Open

Drawing Bezier curves #32

GrahamJoonsar opened this issue Feb 27, 2022 · 7 comments
Labels
enhancement New feature or request

Comments

@GrahamJoonsar
Copy link

I made a way to draw quadratic and cubic bezier curves, but I'm not going to bother with making a pull request cause of the problem described here that I had earlier for the pr with the circles.
https://stackoverflow.com/questions/37344280/git-diff-is-showing-full-file-has-changed-for-a-single-line-change-but-only-for

Heres the code for the two bezier drawing functions:

#define lerp(a, b, t) ((a) + ((b) - (a)) * (t))

void tigrQuadBezier(Tigr * screen, int x0, int y0,
                    int x1, int y1, int x2, int y2,
                    TPixel color){

    float px = x0, py = y0;
    for (float t = 0.0; t <= 1.0; t += 0.01){
        float lx = lerp(x0, x1, t);
        float ly = lerp(y0, y1, t);
        float rx = lerp(x1, x2, t);
        float ry = lerp(y1, y2, t);

        float fx = lerp(lx, rx, t);
        float fy = lerp(ly, ry, t);

        tigrLine(screen, (int)fx, (int)fy, px, py, color);
        px = fx;
        py = fy;
    }
}

void tigrCubicBezier(Tigr * screen, int x0, int y0,
                    int x1, int y1, int x2, int y2,
                    int x3, int y3,
                    TPixel color){

    float px = x0, py = y0;
    for (float t = 0.0; t <= 1.0; t += 0.01){
        float lx = lerp(x0, x1, t);
        float ly = lerp(y0, y1, t);
        float mx = lerp(x1, x2, t);
        float my = lerp(y1, y2, t);
        float rx = lerp(x2, x3, t);
        float ry = lerp(y2, y3, t);

        float gx = lerp(lx, mx, t);
        float gy = lerp(ly, my, t);
        float hx = lerp(mx, rx, t);
        float hy = lerp(my, ry, t);

        float fx = lerp(gx, hx, t);
        float fy = lerp(gy, hy, t);

        tigrLine(screen, (int)fx, (int)fy, px, py, color);
        px = fx;
        py = fy;

    }
}

I also have a test file attached that shows them in action.
build for that file : g++ tigr.c test.cpp -o test -lopengl32 -lgdi32 -lWinmm

test.txt

(Made me do it as a txt file for some reason)

@GrahamJoonsar
Copy link
Author

https://www.geeksforgeeks.org/cubic-bezier-curve-implementation-in-c/amp/

Probably a better implementation

@GrahamJoonsar
Copy link
Author

More efficient bezier without use of lerp function

void tigrQuadBezier(Tigr * screen, int x0, int y0,
                    int x1, int y1, int x2, int y2,
                    TPixel color){

    float px = x0, py = y0;
    for (float t = 0.0; t <= 1.0; t += 0.01){
        const float u = 1-t;
        const float u_2 = u*u; // Good band
        const float t_2 = t*t;

        const float fx = u_2*x0 + 2*u*t*x1 + t_2*x2;
        const float fy = u_2*y0 + 2*u*t*y1 + t_2*y2;

        tigrLine(screen, (int)fx, (int)fy, px, py, color);
        px = fx;
        py = fy;
    }
}

void tigrCubicBezier(Tigr * screen, int x0, int y0,
                    int x1, int y1, int x2, int y2,
                    int x3, int y3,
                    TPixel color){

    float px = x0, py = y0;
    for (float t = 0.0; t <= 1.0; t += 0.01){
        const float t_2 = t*t;
        const float t_3 = t*t_2;
        const float u = 1-t;
        const float u_2 = u*u;
        const float u_3 = u*u_2;

        const float fx = (x0 * u_3) + (3*x1*u_2*t) + (3*x2*u*t_2) + (x3*t_3);
        const float fy = (y0 * u_3) + (3*y1*u_2*t) + (3*y2*u*t_2) + (y3*t_3);

        tigrLine(screen, (int)fx, (int)fy, px, py, color);
        px = fx;
        py = fy;
    }
}

@erkkah
Copy link
Owner

erkkah commented Feb 28, 2022

Cool, thanks. Looks like that will cause a lot of overdrawing, since the curves are always drawn using 100 lines.
I'll focus on getting the other stuff out first, and then look into rasterizing directly, or skipping the feature for now :)

@GrahamJoonsar
Copy link
Author

Yeah I didn’t fine tune the increment of t, but it could probably be incremented by a little more.

@erkkah erkkah added the enhancement New feature or request label Feb 28, 2022
@erkkah
Copy link
Owner

erkkah commented Feb 28, 2022

Just to be clear, it's not a performance (as in cycles) issue. The problem with overdrawing is that it does not play well with alpha. I'll look into it for a later update.

@RandyGaul
Copy link

You would need a different implementation to avoid overdraw issues. Just using an arbitrary increment on t is "guessing" that start and endpoints don't overlap. Using a line rasterization algorithm would work: https://zingl.github.io/bresenham.html

@RandyGaul
Copy link

Actually after some though it should be fine, since tigrLine doesn't draw the last pixel so no overlap. But, it would be in the spirit of tigr to have pixel rasterization functions. Though I certainly don't want to write them!

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

No branches or pull requests

3 participants