私は、WritableImage
を使用して画像を結合して、基本的なテクスチャアトラスクラスを作成しました。私は現在読んでいるビンパッキングアルゴリズムを使用する方が効率的かもしれませんが、すべての画像が同じ幅である私の特別なケースでは、これはうまく動作します。画像を垂直方向に並べるだけです。しかし、現在の構造は、異なるレイアウトのアトラス実装に容易に拡張可能でなければなりません。
アトラス:
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
の全体領域を表すアトラスとgetImage
戻るレイジー初期化Image
の領域を表します。
よくできました。それはあなたの質問に答えたときの私の心にあったものです。私は明示的にキーワード "テクスチャアトラス"を述べておくべきです:-)。 – mipa