且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在JavaFX中使用不同的纹理创建多维数据集

更新时间:2023-11-08 11:26:40

我最终写了一个原始的纹理图集类,并使用WritableImage组合了图像.使用当前正在阅读的bin装箱算法可能会更有效,但是在我的特例中,所有图像都具有相同的宽度,这对我来说很好用.它只是垂直放置图像.但是,其当前结构应易于扩展到布局不同的地图集实施中.

I ended up writing a primitive texture atlas class, combining the images using a WritableImage. It could be more efficient using bin packing algorithms, which I am currently reading up on, but in my special case where all images are the same width this works fine for me. It just lays out the images vertically. However, its current structure should be easily extendable to a differently laid-out atlas implementation.

地图集:

public class TextureAtlas {

    private final Image image;

    private final Map<String, TextureRegion> regions;

    public TextureAtlas(Image image) {
        this.image = image;
        regions = new HashMap<>();
    }

    /**
     * Creates an extremely primitive texture atlas.
     * Could use bin packing eventually.
     */
    public TextureAtlas(Map<String, Image> images) {
        this.regions = new HashMap<>();
        int height = (int) Math.ceil(images.values().stream().mapToDouble(Image::getHeight).sum());
        OptionalDouble w = images.values().stream().mapToDouble(Image::getWidth).max();
        WritableImage i = new WritableImage(w.isPresent() ? (int) w.getAsDouble() : 0, height);
        int h = 0;
        PixelWriter writer = i.getPixelWriter();
        for(Map.Entry<String, Image> entry : images.entrySet()) {
            Image img = entry.getValue();
            PixelReader reader = img.getPixelReader();
            for(int x = 0; x < img.getWidth(); x++)
                for(int y = 0; y < img.getHeight(); y++)
                    writer.setColor(x, y + h, reader.getColor(x, y));
            createRegion(entry.getKey(), img, 0, h, (int) img.getWidth(), (int) img.getHeight());
            h += img.getHeight();
        } this.image = i;
    }

    public TextureRegion createRegion(String name, int x, int y, int width, int height) {
        TextureRegion reg;
        regions.put(name, reg = new TextureRegion(this, x, y, width, height));
        return reg;
    }

    private TextureRegion createRegion(String name, Image image, int x, int y, int width, int height) {
        TextureRegion reg;
        regions.put(name, reg = new TextureRegion(this, x, y, width, height));
        return reg;
    }

    public TextureRegion getRegion(String name) {
        return regions.get(name);
    }

    public Map<String, TextureRegion> getRegions() {
        return Collections.unmodifiableMap(regions);
    }

    public int getWidth() {
        return (int) image.getWidth();
    }

    public int getHeight() {
        return (int) image.getHeight();
    }

    public int getColorAt(int x, int y) {
        if(x >= image.getWidth() || y >= image.getHeight()) return -1;
        return image.getPixelReader().getArgb(x, y);
    }

    public Image getImage() {
        return image;
    }

}

纹理区域:

public class TextureRegion {

    public final TextureAtlas atlas;
    public final int x, y, width, height;
    private Image image;

    public TextureRegion(TextureAtlas atlas, int x, int y, int width, int height) {
        this.atlas = atlas;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public TextureRegion(TextureAtlas atlas, Image image, int x, int y, int width, int height) {
        this.atlas = atlas;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.image = image;
    }

    public int getColorAt(int x, int y) {
        return atlas.getColorAt(this.x + x, this.y + y);
    }

    public double[] getTextureCoordinates(double x, double y) {
        return new double[] {getU(x), getV(y)};
    }

    public double[] scaleTextureCoordinates(double u, double v, double max) {
        return new double[] {scaleU(u, max), scaleV(v, max)};
    }

    public double getU(double x) {
        return (this.x + x) / atlas.getWidth();
    }

    public double getV(double y) {
        return (this.y + y) / atlas.getHeight();
    }

    public double scaleU(double u, double max) { //For conversion from UV systems using a different max value than 1.0
        return getU(u / max * this.width);
    }

    public double scaleV(double v, double max) {
        return getV(v / max * this.height);
    }

    public Image getImage() {
        if(image != null) return image; //Lazily initialize
        else {
            WritableImage img = new WritableImage(width, height);
            PixelWriter writer = img.getPixelWriter();
            PixelReader reader = atlas.getImage().getPixelReader();
            for(int x = 0; x < width; x++)
                for(int y = 0; y < height; y++)
                    writer.setArgb(x, y, reader.getArgb(x + this.x, y + this.y));
            return this.image = img;
        }
    }

}

TextureRegion s代表地图集的一个区域,getImage返回代表整个区域的延迟初始化的Image.

TextureRegions represent a region of the atlas and getImage returns a lazily-initialized Image representing the entire region.