erkkah / tigr

TIGR - the TIny GRaphics library for Windows, macOS, Linux, iOS and Android.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Drawing Bezier curves

GrahamJoonsar opened this issue · comments

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)

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;
    }
}

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 :)

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

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.

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

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!