It looks like Slick's triangulator can't keep up with the complex polygon you've created. I wish I could debug this, but I've never worked with triangulation, and it's a rather complex topic. MatthiasM might be able to provide more insight, since Slick uses one of his triangulators.
Here are a few options:
1. Create the image of the highlight area in Photoshop. This will result in a very efficient, smooth, and reliable output, but it will also take some setup. You will need to "mix and match" images (e.g. corner piece, straight piece, diagonal piece) to get them looking right, and they will never be as dynamic as a path. They also won't be infinitely scalable, if you need zooming. This is really only viable if your paths are predictable and static, like straight lines or
rounded rectangles.
2. Don't use Polygons and Path for rendering, but instead just draw the shapes/lines directly to the screen; e.g. with g.drawArc.
3. Use a simpler polygon that Slick can handle. Or try using boolean operations to see if that results in a working triangulation.
4. Use a different triangulator; for example, poly2tri. This either involves hacking around Slick's codebase, or easier, copying the Slick polygon to a poly2tri polygon, then triangulating, then rendering the resulting triangles with OpenGL.
5. Use Java2D to rasterize the shapes for you. This is a good alternative if the shapes aren't changing every frame. You can also use Java2D's geometry classes for collision/logic, as they may be more robust and more thoroughly tested than Slick's. The nice thing about this is that Java2D (being a software renderer) will appear visually consistent across all platforms (e.g. anti-aliasing will look the same regardless of driver). Plus it includes things like gradients, pattern strokes, etc.
Here's some code for that:
Code:
package slicktests;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Path;
public class TestRasterize extends BasicGame {
public static void main(String[] args) throws SlickException {
new AppGameContainer(new TestRasterize(), 800, 600, false).start();
}
public TestRasterize() {
super("Fill Path");
}
private BufferedImage bufferImg;
private Image imageFull;
private final int SIZE = 1024;
private IntBuffer buffer;
private Image shapeImage;
private List<java.awt.Shape> shapes = new ArrayList<java.awt.Shape>();
private int pointer = 0;
@Override
public void init(GameContainer container) throws SlickException {
//It's assumed that our shape can fit inside the texture "SIZE" 1024x1024
// 1. --- Create an empty slick image
//We will use POWER OF TWO sizes to be safe
imageFull = new Image(SIZE, SIZE);
// 2. --- Create an empty BufferedImage
//Java2D's software rasterizer will utilize this
bufferImg = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
// 3. --- Setup a few shapes for example
GeneralPath path = new GeneralPath();
path.moveTo(50, 120);
path.lineTo(70, 180);
path.lineTo(20, 140);
path.lineTo(80, 140);
path.lineTo(30, 180);
path.closePath();
shapes.add(path);
path = new GeneralPath();
path.moveTo(120, 180);
path.quadTo(150, 120, 180, 180);
path.closePath();
shapes.add(path);
path = new GeneralPath();
path.moveTo(220, 150);
path.curveTo(240, 130, 280, 160, 300, 140);
path.lineTo(300, 180);
path.quadTo(260, 160, 220, 180);
path.closePath();
shapes.add(path);
path = new GeneralPath();
path.moveTo(360, 100);
path.lineTo(360, 200);
path.lineTo(400, 140);
path.lineTo(320, 120);
path.lineTo(400, 180);
path.lineTo(320, 180);
path.closePath();
shapes.add(path);
// 4. --- create our first shape
createShape(shapes.get(pointer));
}
/**
* Uses Java2D to rasterize the given shape, and then passes the resulting pixels to OpenGL.
* @param shape the shape to rasterize
*/
protected void createShape(java.awt.Shape shape) {
//the bounds which we'll use for rendering...
Rectangle bounds = shape.getBounds();
Graphics2D g2d = (Graphics2D)bufferImg.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.clearRect(0, 0, bufferImg.getWidth(), bufferImg.getHeight());
g2d.setColor(java.awt.Color.white);
g2d.fill(shape);
//now we pass the BufferedImage pixel data to the Slick image...
upload(bufferImg, imageFull);
//now grab the correct portion of our power-of-two texture which we can use for rendering
//NOTE: Java2D's stroke will draw on the OUTSIDE edge, so you may need to use bounds + 1 px
shapeImage = imageFull.getSubImage(bounds.x, bounds.y, bounds.width, bounds.height);
}
/**
* Uploads the source (Java2D) data to OpenGL (Slick). The image sizes must be the same.
* @param source the source image
* @param destination the destination image
*/
public void upload(BufferedImage source, Image destination) {
int width = source.getWidth();
int height = source.getHeight();
if (destination.getWidth() != width || destination.getHeight() != height)
throw new IllegalArgumentException("Slick image size must be == Java2D image");
int size = width * height;
if (buffer == null || buffer.capacity() < size)
buffer = BufferUtils.createIntBuffer(size);
int[] pixels = ((DataBufferInt)source.getRaster().getDataBuffer()).getData();
destination.bind();
buffer.rewind();
buffer.put(pixels, 0, size);
buffer.flip();
GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, width, height,
GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
}
public void render(GameContainer container, Graphics g)
throws SlickException {
shapeImage.draw(50, 50, Color.red);
}
@Override
public void update(GameContainer container, int delta)
throws SlickException {
if (container.getInput().isKeyPressed(Input.KEY_SPACE)) {
pointer++;
if (pointer>=shapes.size())
pointer = 0;
createShape(shapes.get(pointer));
}
}
}