Create a cube using different textures in JavaFX

后端 未结 2 1775
既然无缘
既然无缘 2021-01-28 03:43

How can I create a cube that uses different images for each side?

I would like to choose the images to use dynamically, using the user\'s input.

The obvious solu

相关标签:
2条回答
  • 2021-01-28 04:05

    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.

    Atlas:

    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;
        }
    
    }
    

    Texture region:

    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;
            }
        }
    
    }
    

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

    0 讨论(0)
  • 2021-01-28 04:08

    Why don't you just copy the separate images into a single one? You can even do that inside your program via a canvas and a snapshot of it.

    0 讨论(0)
提交回复
热议问题