loading Texture java.lang.ArrayIndexOutOfBoundsException:

Started by jhovarie, April 03, 2018, 07:16:28

Previous topic - Next topic

jhovarie

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.

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

josephdoss

Here's how I load png images with an alpha channel.

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:

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:

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
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();


KaiHH

Change the order of the for loops and the way you compute the pixel from both loop indices.
This:
for(int i = 0; i < width; i++) {
    for(int j = 0; j < height; j++) {
        int pixel = pixels_raw[i*width+j];

should become:
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