При работе над Java-приложением, которое требует отрисовки спрайтов, я думал, что вместо того, чтобы загружать файл .png или .jpg в качестве Image
или BufferedImage
, я мог бы загрузить массив byte[]
содержащие индексы для цветовой палитры (16 цветов на палитре, поэтому два пикселя на byte
), а затем визуализируйте это.Быстрое рендеринг байтов на холст с цветовой палитрой
Метод, который я в настоящее время формирует BufferedImage
из byte[]
массива и цветовой палитры при инициализации, принимая дополнительное время для инициализации, но работает ровно после того, как та, которая работает хорошо, но есть только 4 спрайты в программе до сих пор. Я волнуюсь, что, когда есть более 100 спрайтов, их хранение как BufferedImages
будет слишком облагаться налогом. И не только это означало бы 1 BufferedImage
за спрайт, но на самом деле 1 изображение для каждой комбинации спрайтов и палитр, которые я хотел бы использовать.
Эта функция создает BufferedImage:
protected BufferedImage genImage(ColorPalette cp, int width, int height){ //Function to generate BufferedImage to render from the byte[]
BufferedImage ret = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); //Create the Image to return
for(int j=0; j<height; j++){ //Run a for loop for each pixel
for(int i=0; i<width; i++){
int index = (j * width + i)/2; //Get the index of the needed byte
int value = image[index] & 0x00ff; //Convert to "unsigned byte", or int
byte thing; //declare actual color index as byte
if(i % 2 == 0)thing = (byte)((value & 0b11110000) >>> 4); //If it's an even index(since it starts with 0, this includes the 1st one), get the first 4 bits of the value
else thing = (byte)(value & 0b00001111); //If it's odd, get the last four bits
ret.setRGB(i, j, cp.getColor(thing & 0x00ff).getRGB()); //Set the pixel in the image to the value in the Color Palette
}
}
return ret;
}
И это один фактически делает его на экран:
public void render(Graphics g, int x, int y){ //Graphics to render to and x/y coords
g.drawImage(texture, x, y, TILE_WIDTH, TILE_HEIGHT, null); //Render it
}
Я экспериментировал с другим методом, который делает из byte[]
непосредственно ж/о необходимость в BufferedImage
, которая теоретически должна была бы сэкономить память, избегая использования BufferedImage
для каждого спрайта, но в итоге она была очень и очень медленной. Потребовалось несколько секунд, чтобы сделать каждый кадр не более 25 спрайтов для рендеринга на экране! Обратите внимание, что g
- объект Graphics
.
private void drawSquare(int x, int y, int scale, Color c){ //Draw each "pixel" to scale
if(g == null){ //If null, quit
return;
}
g.setColor(c); //Set the color
for(int i=x; i<x+scale; i++){ //Loop through each pixel
if(i<0)continue;
for(int j=y; j<y+scale; j++){
if(j<0)continue;
g.fillRect(x, y, scale, scale); //Fill the rect to make the "pixel"
}
}
}
public void drawBytes(byte[] image, int x, int y, int width, int height, int scale, ColorPalette palette){ //Draw a byte[] image with given byte[], x/y coords, width/height, scale, and color palette
if(image.length < width * height/2){ //If the image is too small, exit
return;
}
for(int j=0; j<height; j++){ //Loop through each pixel
for(int i=0; i<width; i++){
int index = (j * width + i)/2; //Get index
int value = image[index]; //get the byte
byte thing; //get the high or low value depending on even/odd
if(i % 2 == 0)thing = (byte)((value & 0b11110000) >>> 4);
else thing = (byte)(value & 0b00001111);
drawSquare((int)(x + scale * i), (int)(y + scale * j), scale, palette.getColor(thing)); //draw the pixel
}
}
}
Так есть более эффективный способ сделать эти byte[]
массивы без необходимости BufferedImage
-х? Или будет действительно не проблематично иметь несколько сотен BufferdImage
, загруженных в память?
EDIT: Я также пробовал использовать методы no-BufferedImage, но с g
как один большой BufferedImage, которому все визуализируется, и затем отображается на Canvas
. Основное различие заключается в том, что g.fillRect(...
в этом методе изменен на g.setRGB(...
, но он был так же медленным.
EDIT: Образы, с которыми я имею дело, - 16x16 и 32x32 пикселя.
BufferedImage занимает очень мало памяти, кроме растровых данных (массив байтов). Я сомневаюсь, что вы заметили какую-либо разницу в этой оптимизации. – VGR