4
\$\begingroup\$

The recommended method for making a border around a shape using LibGdx is to draw a larger version of the shape to serve as the border, then draw the shape over the larger image.

shapeRenderer.setColor(borderColor);
shapeRenderer.circle(x, y, radius + borderWidth);
shapeRenderer.setColor(shapeColor);
shapeRenderer.circle(x, y, radius);

This works well most of the time, but if you want shapeColor to have any opacity less than 1, it fails. The problem is that you can see the borderColor through the shape, and the colors are blended.

Is there anyway to fix this issue?

\$\endgroup\$
3
\$\begingroup\$

One thing you could try is to draw the border as a line with a thickness first, then draw the inner part of the circle as a filled shape;

shapeRenderer.begin(ShapeType.Line)
Gdx.gl10.glLineWidht(borderWidth);
shapeRenderer.setColor(borderColor);
shapeRenderer.circle(x, y, radius + borderWidth);
shapeRenderer.end();

shapeRenderer.begin(ShapeType.Filled)
shapeRenderer.setColor(shapeColor);
shapeRenderer.circle(x, y, radius);
shapeRenderer.end();

You might have to query for the capabilities for the line width using glGet and asking for 'GL_ALIASED_LINE_WIDTH_RANGE' and 'GL_SMOOTH_LINE_WIDTH_RANGE' (opengl reference), and it will possibly make the drawing device dependent.

If that does not work, you could try render to texture first, using a frame buffer with no blending, then draw that buffer (with blending) to screen;

// Position and size of circle, and border
float circleX = 100; 
float circleY = 100;

float radius=100;
float border=10;

// Total size of the buffer
int size = (int)((radius+border)*2);

// Create the buffer and get a region to it
FrameBuffer buffer = new FrameBuffer(Format.RGBA8888, size, size, false);
TextureRegion region = new TextureRegion(buffer.getColorBufferTexture());
region.flip(false, true); 

// Begin the buffer, any draw calls made after this affect the buffer, not the "screen"
buffer.begin();
ShapeRenderer renderer = new ShapeRenderer();
renderer.begin(ShapeType.Filled);
// Draw border, centered on buffer
renderer.setColor(new Color(1, 0, 0, 1.0f)
renderer.circle(size / 2, size / 2, radius + border);

// Draw center, centered on buffer
renderer.setColor(new Color(1, 1, 1, 0.5f)
renderer.circle(size / 2, size / 2, radius);

renderer.end(); // shapes done
buffer.end(); // buffer done

// Now render the buffer onto the "screen"
SpriteBatch batch = new SpriteBatch();
batch.begin();
// Move to the buffer offset representing the circle's position
batch.draw(region, circleX - size, circleY - size);
batch.end();

Obviously, in the example above, try to new up the buffer, region, and renderer outside of your render method so that you don't pay the performance penalty of doing that every time.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for the suggestion. I don't want to rely on this if possible because of the line width limitations you mentioned. I think I may have to go with some sort of special blending but I'm not sure what to use since I'm not too familiar with OpenGL. \$\endgroup\$ – you786 Jun 8 '15 at 18:52
  • \$\begingroup\$ Ok, that's fair. I've added an explanation for my other suggestion where you render to buffer first. \$\endgroup\$ – bornander Jun 9 '15 at 7:54

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.