Hello Guest

loading Texture java.lang.ArrayIndexOutOfBoundsException:

  • 2 Replies
  • 3335 Views
Hello I need help about loading the texure.. I used this code for loading texture if I load image with same width and height size
it works perfect it doest not crush.. but if I load image with different width and height size it return error java.lang.ArrayIndexOutOfBoundsException:

Any help? the codes looks like this.

Code: [Select]
public Texture(BufferedImage bi) {
try {
//bi = ImageIO.read(new File(filename));
width = bi.getWidth();
height = bi.getHeight();

int[] pixels_raw = new int[width * height * 4];
pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);

ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);
for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
int pixel = pixels_raw[i*width+j];
pixels.put((byte)((pixel >> 16) & 0xFF));//RED
pixels.put((byte)((pixel >> 8) & 0xFF));//GREEN
pixels.put((byte)(pixel & 0xFF)); //BLUE
pixels.put((byte)((pixel >> 24) & 0xFF)); //Alpha
}
}
pixels.flip();

id = glGenTextures();

glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width,height, 0, GL_RGBA, GL_UNSIGNED_BYTE,pixels);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width,height, 0, GL_RGBA, GL_BYTE,pixels);
}catch(Exception e) {
e.printStackTrace();
}
}

*

Offline josephdoss

  • *
  • 15
  • redbirdflyfree.blogspot.com
    • game dev
Re: loading Texture java.lang.ArrayIndexOutOfBoundsException:
« Reply #1 on: April 03, 2018, 17:38:19 »
Here's how I load png images with an alpha channel.

Code: [Select]

public static ByteBuffer ioResourceToByteBuffer(String resource, int bufferSize) throws IOException {
ByteBuffer buffer;
File file = new File(resource);
URL url = globalStatic.class.getResource(resource.replace("resources",""));

if (file.isFile())
{
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
fc.close();
fis.close();
} else
{ buffer = BufferUtils.createByteBuffer(bufferSize);
InputStream source = url.openStream();
if (source == null)
throw new FileNotFoundException(resource);
try {
ReadableByteChannel rbc = Channels.newChannel(source);
try {
while (true) {
int bytes = rbc.read(buffer);
if (bytes == -1)
break;
if (buffer.remaining() == 0)
buffer = resizeBuffer(buffer, buffer.capacity() * 2);
}
buffer.flip();
} finally {
rbc.close();
}
} finally {
source.close();
}
}
return buffer;
}



Using it looks like this:

Code: [Select]

IntBuffer textureWidthFront = BufferUtils.createIntBuffer(1);
IntBuffer textureHeightFront = BufferUtils.createIntBuffer(1);
IntBuffer textureComponentsFront = BufferUtils.createIntBuffer(1);
ByteBuffer textureDataFront;
String textureSourceFront = "resources" + "/" + "actors"  + "/" + "skins" + "/" + "human3" + "/" + "outfits" + "/" + "shirts" + "/" + "nude" + "/" + "chest_male_front.png";
int textureIDFront = -1;
public int GLTextureCoordLocationFront;
public int GLTextureImageUniformFront;

try {
ByteBuffer textureDataFront = stbi_load_from_memory(globalStatic.ioResourceToByteBuffer(textureSourceFront, 20 * 1024), textureWidthFront, textureHeightFront, textureComponentsFront, 4);
} catch (Exception e) {
System.out.println(className + " constructor : error thrown making the texture message:" + e.getMessage() + " stacktrace:" + e.getStackTrace());
}


I hope that helps ya.




I really don't like this line:

Code: [Select]
int pixel = pixels_raw[i*width+j];
Let's say width is 3 and height is 2. So, a 3x2 or 6 cell array.
When i is 2 and j is 1, i*width+j is 2*3+1 or 7.... there is no index 7 in an array of six cells.
Multiplying it by 4 does get around the size issue for awhile, but if you go out to an extreme example, the 4 doesn't save you.

width : 500,000
height: 20,000
width*height*4 : 40,000,000,000

i:499,999
j:19,999
index : 499,999*500,000+19,999 = 249,999,519,999 which is way bigger than 40 billion.

I'd propose you make a counter variable instead of trying to do the math inside the for loop
Code: [Select]
int[] pixels_raw = new int[width * height ];
pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);
int counterIndex=0;
             
 ByteBuffer pixels = BufferUtils.createByteBuffer(width * height *4);
 for(int i = 0; i < width; i++) {
          for(int j = 0; j < height; j++) {
                 int pixel = pixels_raw[counterIndex];
                 pixels.put((byte)((pixel >> 16) & 0xFF));//RED
                 pixels.put((byte)((pixel >> 8) & 0xFF));//GREEN
                 pixels.put((byte)(pixel & 0xFF));       //BLUE
                 pixels.put((byte)((pixel >> 24) & 0xFF)); //Alpha
                 counterIndex++;
         }
 }
pixels.flip();
« Last Edit: April 03, 2018, 18:38:36 by josephdoss »

*

Offline KaiHH

  • ****
  • 334
Re: loading Texture java.lang.ArrayIndexOutOfBoundsException:
« Reply #2 on: April 03, 2018, 20:48:34 »
Change the order of the for loops and the way you compute the pixel from both loop indices.
This:
Code: [Select]
for(int i = 0; i < width; i++) {
    for(int j = 0; j < height; j++) {
        int pixel = pixels_raw[i*width+j];
should become:
Code: [Select]
for(int j = 0; j < height; j++) { // <- first iterate over all lines
    for(int i = 0; i < width; i++) { // <- and for each line over all pixels within that line
        int pixel = pixels_raw[j*width+i]; // <- multiply the 'j' and not 'i' by width