Partially filling an arc with a proportional gradient

public static void fillScaledArc(Graphics g, int x, int y, int r, float scale, int angle1, int angle2, Color c1, Color c2)
{
Graphics2D g2 = (Graphics2D) g;
GradientPaint gp = new GradientPaint(x, y, c1, x, y+(rscale), c2, false);
g2.setPaint(gp);
g.fillArc(x, y, (int)(r
scale),(int)(r*scale),angle1,angle2);
}

The above code will draw an arc and then fill it with a gradient from top to bottom. Let’s say that I pass Color.green and Color.red as my c1 and c2 arguments. Now, let’s say that I want to only fill 50% of this arc. However, I want the color to range from half-way to green (in this case kind of greenish-orange) to red . How would I rewrite this function to do this by passing it a percentage (i.e. .5 or .75)?

I’m using this to dynamically draw a health meter on one half of a circle.

I am not really sure what you try to archive, but a good idea would maybe to set a complex clip using the clip(shape) function, which should be even accalerated using the OpenGL pipeline.

lg Clemens

That’s a good idea, I completely forgot about clipping as an alternative. However, how would you clip an arc like that (my geometry is terrible)?

Basically you have a semicirlce that has a gradient in it. The gradient represents the player’s life. So as their life goes down, less of the gradient is visible (cut off as a straight horizontal line somewhere on the meter).

Since you are needing something fairly simple. Why not make 2 images.

Image 1 has the arc outline with an empty center (or a dark pattern)

Image 2 has the gradient pattern in an arc shape. Then use the drawImage method that allows you to select an x,y area from the source image.
As the health goes down grab a smaller section of the source image. Depending on the size of the arc you could even create all the health level images when the game starts.

I think a shortcut to this would be just to draw the entire arc with the gradient and save it as an image, I could then only draw whatever percentage of the image that I needed with the function listed above. So how would you get the following code into an image to be manipulated this way?

 Graphics2D g2 = (Graphics2D) g;
 GradientPaint gp = new GradientPaint(x, y, c1, x, y+(r*scale), c2, false);
 g2.setPaint(gp);
 g.fillArc(x, y, (int)(r*scale),(int)(r*scale),angle1,angle2);

oh, and I’m trying to do this dynamically since the scale changes frequently which is why I didn’t just save the image off once and load it again later.

gc is GraphicsConfiguration
Look up the createCompatibleImage() in the docs for what to do with transparencyType.

BufferedImage healthMeter = gc.createCompatibleImage(w,h,transparencyType);
g=healthMeter.getGraphics();

Then use this g as you normally would except now its being drawn to the image you made.

Okay, so what is wrong with this then, it doesn’t appear to be doing anything…

public void setCompositeImage()
{
	GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    int  transparency = Transparency.BITMASK;
	GraphicsDevice gs = ge.getDefaultScreenDevice();
    GraphicsConfiguration gc = gs.getDefaultConfiguration();
	if (gc != null)
	{
		BufferedImage healthMeter = gc.createCompatibleImage(100,100, transparency);
		Graphics g=healthMeter.getGraphics();
		
		UtilityFunctions.fillGradientArc(g, 0,0,100,90,180,Color.green, Color.red);
		UtilityFunctions.fillGradientArc(g, 0,0,100,270,180,Color.blue, new Color(149, 0, 51));
		g.setColor(Color.black);
		g.drawOval(0,0,100,100);
		g.fillOval(13,13,75,75);
		if (healthMeter != null)
		{
			mediaTracker = new MediaTracker(this);
			mediaTracker.addImage(healthMeter, 1);
			// Wait until all images have loaded
			try {mediaTracker.waitForAll();} catch (Exception e) {e.printStackTrace();}
			this.setOriginalImage(healthMeter);
			repaint();
		}
	}
}

Sorry guys, the above actually works. It was somewhere else in my code that I had a problem.

One thing that isn’t quite right is the anti-aliasing. Using the draw code in a paint method of a component looks much better than this one does. For some reason this was only corrected after changing the transparency to:

transparency = Transparency.TRANSLUCENT;

and adding…

Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);