Main Menu

glDrawPixles

Started by CaseyB, August 09, 2005, 13:33:57

Previous topic - Next topic

CaseyB

I am trying to get a BufferedImage and extract the pixel data to feed into glDrawPixels(), but it keeps giving me an exception.  Here is the StackTrace:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Number of remaining buffer elements is 502865, must be at least 1508598
	at org.lwjgl.BufferChecks.checkBufferSize(BufferChecks.java:177)
	at org.lwjgl.BufferChecks.checkBuffer(BufferChecks.java:187)
	at org.lwjgl.opengl.GL11.glDrawPixels(GL11.java:2026)
	at Canvas.paintGL(Canvas.java:123)
	at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:256)
	at sun.awt.RepaintArea.paintComponent(Unknown Source)
	at sun.awt.RepaintArea.paint(Unknown Source)
	at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)


and the relevant code:
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Image img = viewport.CreateImage(null);
        BufferedImage bufImg = gc.createCompatibleImage(img.getWidth(null), img.getHeight(null), Transparency.OPAQUE);

        System.out.println(bufImg);
        
        DataBuffer dataBuffer = bufImg.getData().getDataBuffer();
        
        IntBuffer image = IntBuffer.allocate(dataBuffer.getSize());
        image.put(dataBuffer.getOffsets());
        
        System.out.println("db.size: " + dataBuffer.getSize() + "\nib.rem: " + image.remaining());
        
        GL11.glDrawPixels(img.getWidth(null), img.getHeight(null), GL11.GL_RGB, GL11.GL_INT, image);


Can anyone help me figure this out?  I really have no idea how this works!

napier

When you allocate the intbuffer (IntBuffer.allocate(dataBuffer.getSize())) it's making a buffer with 502866 ints.  It looks like glDrawPixels() is expecting bytes of RGB data (502865 x 3 = 1508595).

Last time I used DrawPixels, I loaded the image pixels into a ByteBuffer, then called DrawPixels like so:

ByteBuffer pixelBuffer; // load pixels into byteBuffer
	...
        GL11.glDrawPixels(img.w, img.h, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixelBuffer);


If you need image loading code try this:

   http://potatoland.com/code/gl/GLImage.java

Look at loadImage(), and to convert byte order: convertARGBtoRGBA()

FYI glDrawPixels() is very slow.  If you're doing this every frame it's better to draw the image as a texture on a quad.
penGL/Java/LWJGL demos and code: http://potatoland.org/code/gl

CaseyB

Thank you very much!  I'll try that out!  Also I am only repainting about once a minute, but I will also try it as a texture!  Thank you so much!

CaseyB

It's still not working for me!  The grabbing keeps being interrupted.  The trouble I am having is that I am not loading from a file, I have a weird image format that I can convert into a BufferedImage. :?  How would I go about loading a BufferedImage as a texture?

napier

The GLImage class that I linked above has code for loading an awt Image, but BufferedImage should be very similar.  

If you mean that the pixel grabbing is interrupted, then something's broken with the BufferedImage data, not with the OpenGL part.

Once you get a BufferedImage loaded you can create a texture with the image pixels.  I use this function:

/**
* Create a texture from the given pixels in RGBA format.  Set the texture
* to repeat in both directions and use LINEAR for magnification.
*/
public static int makeTexture(ByteBuffer pixels, int w, int h)
{
	// get a new empty texture
	int textureHandle = allocateTexture();
	// 'select' the new texture by it's handle
	GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
	// set texture parameters
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
	// Create the texture from pixels
	GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, w, h, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
	return textureHandle;
}

/**
 * Allocate a texture (glGenTextures) and return the handle to it.
 */
public static int allocateTexture()
{
        IntBuffer textureHandle = allocInts(1);
        GL11.glGenTextures(textureHandle);
        return textureHandle.get(0);
}
penGL/Java/LWJGL demos and code: http://potatoland.org/code/gl

CaseyB

That seems to work, sort of.  It doesn't throw any exception, but it also doesn't display the texture.  It's probably a problem on my end, I'll keep fighting with it!  Thank you very much for your help!!!  :D

CaseyB

Ok, I still can't get it to put the texture on the quad.  here is my code:
// Get the image from the viewport
        Image img = viewport.CreateImage(null);
        
        // Setup Pixelgrabber to load pixels into int[] pixels
        PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null), img.getHeight(null), pixels, 0, img.getWidth(null));
        
        try
        {
            pg.grabPixels();
        }
        catch (Exception e)
        {
            System.out.println("Pixel Grabbing interrupted!");
        }
        
        // Convert ARGB int[] into RGBA byte[], Thanks napier
        bytes = convertARGBtoRGBA(pixels);
        
        // Load byte[] into a ByteBuffer
        ByteBuffer pixelBuffer = ByteBuffer.allocateDirect(bytes.length).put(bytes);
        pixelBuffer.flip();
        
        // Turn ByteBuffer into a texture, also thanks napier
        texture = makeTexture(pixelBuffer, img.getWidth(null), img.getHeight(null));

        // Bind Texture and reverse winding
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
        GL11.glFrontFace(GL11.GL_CW);
        
        // Draw Quad with texture
        GL11.glBegin(GL11.GL_QUADS);
            GL11.glTexCoord2f( 0.0f,  1.0f); GL11.glVertex3f(-(width/2f), -(height/2f), -0.01f);
            GL11.glTexCoord2f( 0.0f,  0.0f); GL11.glVertex3f(-(width/2f),  (height/2f), -0.01f);
            GL11.glTexCoord2f( 1.0f,  0.0f); GL11.glVertex3f( (width/2f),  (height/2f), -0.01f);
            GL11.glTexCoord2f( 1.0f,  1.0f); GL11.glVertex3f( (width/2f), -(height/2f), -0.01f);
        GL11.glEnd();

What I end up with is just a white quad.  Any ideas as to what I'm doinf wrong.  I am new to all of this so if it's a stupid and or obvious problem, I apologize!

CaseyB

CaseyB

Now I can get it to do glDrawPixels() perfectly, but it is very slow.  When I use the exact same data to try to create a texture it doesn't happen.  I just get a blank, white quad!
img = viewport.CreateImage(null);
if(img != null)
{
     int w = img.getWidth(null);
     int h = img.getHeight(null);
     int[] pixels = new int[w*h];
	        	
     PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pixels, 0, w);
     try
     {
          pg.grabPixels();
     }
     catch (Exception e)
     {
          System.out.println("Pixel Grabbing interrupted!");
     }
		        
     byte[] bytes = convertARGBtoRGBA(pixels);	        
     pixelBuffer = ByteBuffer.allocateDirect(bytes.length).put(bytes);
     pixelBuffer.flip();
		        
     texture = makeTexture(pixelBuffer, img.getWidth(null), img.getHeight(null));
}
else
{
     System.err.println("Could not load Glg Data");
     System.exit(-1);
}
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDrawPixels(img.getWidth(null), img.getHeight(null), GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixelBuffer);
GL11.glEnable(GL11.GL_DEPTH_TEST);

Works but...
img = viewport.CreateImage(null);
if(img != null)
{
     int w = img.getWidth(null);
     int h = img.getHeight(null);
     int[] pixels = new int[w*h];
	        	
     PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pixels, 0, w);
     try
     {
          pg.grabPixels();
     }
     catch (Exception e)
     {
          System.out.println("Pixel Grabbing interrupted!");
     }
		        
     byte[] bytes = convertARGBtoRGBA(pixels);	        
     pixelBuffer = ByteBuffer.allocateDirect(bytes.length).put(bytes);
     pixelBuffer.flip();
		        
     texture = makeTexture(pixelBuffer, img.getWidth(null), img.getHeight(null));
}
else
{
     System.err.println("Could not load Glg Data");
     System.exit(-1);
}
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glFrontFace(GL11.GL_CW);
        
GL11.glBegin(GL11.GL_QUADS);
     GL11.glTexCoord2f( 0.0f,  1.0f); GL11.glVertex3f(-(width/2f), -(height/2f), -0.01f);
     GL11.glTexCoord2f( 0.0f,  0.0f); GL11.glVertex3f(-(width/2f),  (height/2f), -0.01f);
     GL11.glTexCoord2f( 1.0f,  0.0f); GL11.glVertex3f( (width/2f),  (height/2f), -0.01f);
     GL11.glTexCoord2f( 1.0f,  1.0f); GL11.glVertex3f( (width/2f), -(height/2f), -0.01f);
GL11.glEnd();

Does not!  I used the code that napier posted, so it's got to be something that I am doing wrong somewhere else.  :x

CaseyB

Turns out that the sides of the image that was being created on the fly weren't powers of two and instead of throwing an exception, they were just not being displayed!  As a temporaty work around I just grabbed a region of pixels that WERE a power of 2!  :shock:  I think I'll just stare at the pretty pictrues for a while and be thankful that that part is sorted!

CaseyB

napier

Yup, as you've already discovered, texture images need to have dimensions that are powers of two.  

Sounds like you're hacking through the typical opengl issues.  Do you have the Red book?  If not, this is required reading:

    http://www.opengl.org/documentation/red_book_1.0

An earlier edition of the book is online:

   http://www.rush3d.com/reference/opengl-redbook-1.1/
penGL/Java/LWJGL demos and code: http://potatoland.org/code/gl

CaseyB

No, I don't have it, I should get it though, it sounds like the OpenGL Bible!  There is also a blue book isn't there?  What's the difference?

Orangy Tang

The red book is an introduction and explaination of OpenGL. The blue book is a reference of all OpenGL functions (the javadoc if you will). If you can live with only a reference for 1.1 then you can save yourselve some cash and just use MSDN.

CaseyB

Good to know, Thanks!