3
\$\begingroup\$

I've been thinking of ways to render a rounded rectangle in libgdx. I haven't found a pre-built way in the documentation. I've looked at:

  • ShapeRenderer, but that's apparently quite expensive performance-wise and I'll have to compose it of a polygon perhaps or use circles and rectangles.
  • The Mesh class, which would probably perform well but is complex to use for such a simple shape. Again, I'd have to create the polygon myself with an algorithm for different sizes of rounded rectangles.

Can someone point me in the right direction?

\$\endgroup\$
  • \$\begingroup\$ just make a texture with rounded corners (even a ninepatch) and use that \$\endgroup\$ – wes Apr 8 '14 at 14:54
  • \$\begingroup\$ I'd like a more flexibility than a ninepatch or texture will provide. Such as being able to input the radius for the corners (ideally) and being perfectly scalable. \$\endgroup\$ – lostpebble Apr 8 '14 at 15:24
1
\$\begingroup\$

You can procedurally generate a rounded rectangle. You should probably use ShapeRenderer for this, as its rect and arc methods provide exactly what you need (five filled rectangles -- or two that overdraw -- and four filled arcs produce a rounded rectangle). I would strongly encourage you to build your rectangle this way and only worry about more complicated solutions if you actually see performance issues.

If you really want to avoid ShapeRenderer, you can build the geometry yourself and store it into a Mesh for rendering. You'll have to produce actual triangles to do so, so you'll want to approximate the arcs using triangles organized like a triangle fan (you may not want to use actual triangle fans, since they are poorly-supported and also because you can't represent the rest of the rounded rectangle with them, so you'd end up with many draw calls per rectangle rather than a single draw call if you were generate the geometry as a single indexed triangle list).

You should then cache this Mesh object (or several of them, one for each "resolution" of arc representation) and re-use it for every rectangle you want to draw. This may be more efficient than ShapeRenderer if you put the time and effort into it, but it's also going to be more work on your part.

A related option would be to continue to use a ninepatch, but to generate the textures you use for the rounded corners with ShapeRenderer once, using very high-resolution calls to arc to ensure you have sufficient visual fidelity for your needs (you'll need to tweak the input, but that would be easy). This is likely the most efficient, since a ninepatch uses much less geometry then a mesh would to represent the same thing, unless you have some other needs that make ninepatches unusable.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks. Using the ShapeRenderer with arcs and rectangles seems like the best place for me to dive into this. Performance-wise, if I do run into issues I'll go for the Mesh. The maximum amount of rounded rectangles I'd have to render at one go would probably be around 50-60 or so. \$\endgroup\$ – lostpebble Apr 8 '14 at 23:19
5
\$\begingroup\$

In case it's useful for anyone, here's my extension of LibGDX's ShapeRenderer to draw rectangles with rounded corners, using Josh Petrie's approach of drawing five rectangles and four arches.

I chose it over the two overlapping rectangles approach because it works well with transparency.

public class MyShapeRenderer extends ShapeRenderer{
    /**
    * Draws a rectangle with rounded corners of the given radius. 
    */ 
    public void roundedRect(float x, float y, float width, float height, float radius){
        // Central rectangle
        super.rect(x + radius, y + radius, width - 2*radius, height - 2*radius);

        // Four side rectangles, in clockwise order
        super.rect(x + radius, y, width - 2*radius, radius);
        super.rect(x + width - radius, y + radius, radius, height - 2*radius);
        super.rect(x + radius, y + height - radius, width - 2*radius, radius);
        super.rect(x, y + radius, radius, height - 2*radius);

        // Four arches, clockwise too
        super.arc(x + radius, y + radius, radius, 180f, 90f);
        super.arc(x + width - radius, y + radius, radius, 270f, 90f);
        super.arc(x + width - radius, y + height - radius, radius, 0f, 90f);
        super.arc(x + radius, y + height - radius, radius, 90f, 90f);
    }
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Have you suggested this in a pull request? \$\endgroup\$ – TheChubbyPanda Aug 3 '19 at 13:31
1
\$\begingroup\$

When rendering 3D graphics you are always using a 3D mesh in some form or other. (Ignore the deprecated immediate mode.) So if you have a library that offers you to render a cube or a teapot, the underlying implementation basically has (or generates) a 3D mesh to render the shape.

The straightforward way of rendering any non trivial shape is build the shape in a 3D modeling package, load the shape and render that. (Yes, rounded corners make the shape non trivial.)

My advice is to build the box in a tool like Blender and save the model in either the OBJ or PLY format. These formats are well known and text based and as a result have either prebuilt parses or are trivial to read. The given vertex data can then be fed into the Mesh class you mentioned.

The upside is that, from that point on you can build and render other non-trivial objects.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer but I think I wasn't specific enough in my question. I'd like to render a 2D shape. I was assuming the Mesh class was capable of 2D rendering and perhaps I am mistaken there. Unless what you're saying is I should grab the 2D shape from some of the vertices of the 3D model, but that won't allow for the kind of flexibility I'm looking for on the corners of the rectangle. \$\endgroup\$ – lostpebble Apr 8 '14 at 15:33
  • \$\begingroup\$ In what way is it not possible to render a 2D shape with a 3D model? Just build the shape with z=0 for all vertexes. In 90% of the time it is faster to just whip up a model in blender than trying to compute the vertexes in code (or by hand). \$\endgroup\$ – rioki Apr 10 '14 at 8:30
  • \$\begingroup\$ But that doesn't allow for flexible corners. I'd like to be able to set the radius at will. With this method I'd have to create many different models to account for every possible radius. \$\endgroup\$ – lostpebble Apr 10 '14 at 8:34
  • \$\begingroup\$ True that. But then it is also not stated in the question. \$\endgroup\$ – rioki Apr 10 '14 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.