javalwjgl

How to draw a rectangle in OpenGL with rounded corners?


I want to draw a rectangle with rounded corners. An example is this:

rect

For reasons, I prefer to use intermediate mode, but shaders are fine either.
How can I do so in OpenGL? I want to have a method like:

public static void drawRectWithRoundedCorners(float x, float y, float width, float height, float radius, Color color) {
    // code
}

I could not find any instructions on it.

I tried to use a texture, the problem was the corners also got stretched so now I cannot use an image.


Solution

  • You create geometry for the circumference and render it ... so shorten the rectangle lines by radius from all sides and add circular arc using circle parametric equation ... (~36 lines per whole circle is usually enough), another option is use shaders and compute the distance to rounded rectangle in fragment shader and simply discard; pixels outside...

    I do not code in JAVA but C++ is close enough so here C++/old api GL example:

    void drawRectWithRoundedCorners(float cx,float cy, float dx, float dy, float r,unsigned __int32 rgba)
        {
        int i;
        float x0,y0,x,y,a=0.0;
        const int n=9;
        const float da=1.5707963267948966192313216916398/float(n);
        dx-=r+r;
        dy-=r+r;
        glColor4ubv((unsigned __int8*)(&rgba));
        glBegin(GL_TRIANGLE_FAN);
        glVertex2f(cx,cy);
        x0=cx+(0.5*dx);
        y0=cy+(0.5*dy);
        for (i=0;i<n;i++,a+=da)
            {
            x=x0+(r*cos(a));
            y=y0+(r*sin(a));
            glVertex2f(x,y);
            }
        x0-=dx;
        for (i=0;i<n;i++,a+=da)
            {
            x=x0+(r*cos(a));
            y=y0+(r*sin(a));
            glVertex2f(x,y);
            }
        y0-=dy;
        for (i=0;i<n;i++,a+=da)
            {
            x=x0+(r*cos(a));
            y=y0+(r*sin(a));
            glVertex2f(x,y);
            }
        x0+=dx;
        for (i=0;i<n;i++,a+=da)
            {
            x=x0+(r*cos(a));
            y=y0+(r*sin(a));
            glVertex2f(x,y);
            }
        glVertex2f(x,cy+(0.5*dy));
        glEnd();
        }
    

    to improve speed you could have the 36 cos and sin values hardcoded in a table and as cos is just shifted sin you can do this:

    void drawRectWithRoundedCorners(float cx,float cy, float dx, float dy, float r,unsigned __int32 rgba)
        {
        int i;
        float x0,y0,x,y;
        static const float sina[45]={0,0.1736482,0.3420201,0.5,0.6427876,0.7660444,0.8660254,0.9396926,0.9848077,1,0.9848078,0.9396927,0.8660255,0.7660446,0.6427878,0.5000002,0.3420205,0.1736485,3.894144E-07,-0.1736478,-0.3420197,-0.4999996,-0.6427872,-0.7660443,-0.8660252,-0.9396925,-0.9848077,-1,-0.9848078,-0.9396928,-0.8660257,-0.7660449,-0.6427881,-0.5000006,-0.3420208,-0.1736489,0,0.1736482,0.3420201,0.5,0.6427876,0.7660444,0.8660254,0.9396926,0.9848077};
        static const float *cosa=sina+9;
        dx-=r+r;
        dy-=r+r;
        glColor4ubv((unsigned __int8*)(&rgba));
        glBegin(GL_TRIANGLE_FAN);
        glVertex2f(cx,cy);
        x0=cx+(0.5*dx);
        y0=cy+(0.5*dy);
        for (i=0;i<9;i++)
            {
            x=x0+(r*cosa[i]);
            y=y0+(r*sina[i]);
            glVertex2f(x,y);
            }
        x0-=dx;
        for (;i<18;i++)
            {
            x=x0+(r*cosa[i]);
            y=y0+(r*sina[i]);
            glVertex2f(x,y);
            }
        y0-=dy;
        for (;i<27;i++)
            {
            x=x0+(r*cosa[i]);
            y=y0+(r*sina[i]);
            glVertex2f(x,y);
            }
        x0+=dx;
        for (;i<36;i++)
            {
            x=x0+(r*cosa[i]);
            y=y0+(r*sina[i]);
            glVertex2f(x,y);
            }
        glVertex2f(x,cy+(0.5*dy));
        glEnd();
        }
    

    This is preview of drawRectWithRoundedCorners(200,200,100,50,10,0x00204080);:

    preview