Bizarre ReadPixel behavior

When writing a 4d visualization app in Java, I save the state of the window using readPixel so I can write out an image. I am using JOGL, but it’s a very thin wrapper on OpenGL. I am hoping there is a problem with the way calls are happening as opposed to some horrible bug in the parameter passing of the API itself.

First, to get the size of the current window (which has not been manually resized since the beginning of the run:)

gl.glGetIntegerv(GL.GL_VIEWPORT, view);
int w = view[2]+1, h = view[3]+1;

I added one because doing so made the code work, because setting w = view[2] results in a very bad looking picture (see http://davidson.dl.stevens-tech.edu/personal/dkruger/bad1.png))

The following code works well, for the particular size we are generating right now, but when I change the size, it has the same sort of byte alignment problems
I am pretty sure that the image saving code works, because a test pattern invariably comes out the correct size.

BufferedImage image = new BufferedImage( w-1, h-1, BufferedImage.TYPE_BYTE_INDEXED );
// BufferedImage image = new BufferedImage( w, h, BufferedImage.TYPE_BYTE_INDEXED );
DataBufferByte dbRaster = (DataBufferByte)image.getRaster().getDataBuffer();

byte[] buf = new byte[wh3];
byte[] b = dbRaster.getData();

gl.glFlush();
gl.glReadBuffer( GL.GL_FRONT );
gl.glReadPixels( 0, 0, w, h, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, buf);
gl.glFlush();

This should have just put all the rgb bytes into array buf, which is upside-down from png perspective. But whether I comment out the flipVert or not, it is not only upside-down, it is shifted by one pixel (causing a 45 degree slant in the drawing) and even more disturbing, the colors go crazy, indicating that the rgb bytes are not even aligned properly. If it was my processing, then commenting and uncommenting flipVert should solve/recreate the problem. It does not. It also swaps halves of the image left and right. So I “fixed” the code with these awful -1 that I do not really understand, but then, when I change the size of the window and run again, my horrible “fix” no longer works. I don’t think it’s the rgbToIndexed routine (though I include it below anyway) because the same problem appears if I write an RGB png file without the conversion to indexed.

Somehow, it seems as though the buffer is not getting copied in correctly aligned, certainly is not the size that I am asking for. Is there anything obvious I am doing wrong with the readPixel call??

			
flipVert(buf, w, h);
//System.out.println("buflen="+b.length + " w=" + w + " h=" + h);
rgbToIndexed(buf, b,w);
shiftHoriz(b, w-1, h,(w-1)/2);

  public static void shiftHoriz(byte[] buf, int w, int h, int w2) {
  	byte temp;
		for (int y = 0, row = 0; y < h-1; y++, row += w) {
			for (int x = 0; x< w2; x++) {
				temp = buf[row + x];
				buf[row + x] = buf[row + w2+x];
				buf[row+w2+x] = temp;
			}
		}
  }

public static void flipVert(byte[] buf, int maxX, int maxY) {
  byte r, g, b;
  for (int y = 0, top = 0, bottom = 3*maxX * (maxY-1); y<(maxY/2); y++, bottom-=maxX*3, top+=3*maxX) {
    for (int x = 0; x<3*maxX; x+=3) {
      r = buf[bottom+x  ];
      g = buf[bottom+x+1];
      b = buf[bottom+x+2];

      buf[bottom+x  ] = buf[top+x  ];
      buf[bottom+x+1] = buf[top+x+1];
      buf[bottom+x+2] = buf[top+x+2];
				
      buf[top+x  ] = r;
      buf[top+x+1] = g;
      buf[top+x+2] = b;
    }
  }
}

public static void rgbToIndexed(byte[] rgb, byte[] ind, int w) {
  byte clr = 0;
  for (int i = 0, j = 0; i < ind.length; i++, j+=3){
      ind[i] = lookupColor(rgb[j], rgb[j+1], rgb[j+2]);
     }
  }

You’re not handling the packing alignment properly. Check out glPixelStore and the GL_PACK_ALIGNMENT option. The default is 4 byte alignment, and unless you have changes it, you must ensure that each row is properly padded at the end with enough byte so that the next row starts on a multiple of 4 bytes from the start address.

Adn there’s no reason to have those glFlush calls there. They don’t do anything the way you have them.

Astounding!

What I don’t understand is how it could EVER have worked (and it did, selectively).

gl.glPixelStore(GL.GL_PACK_ALIGNMENT, 1);

is in fact just what you need.

Thanks!