gluScaleImage in jogl-1.1.1-rc2

Ken & al:

(CAVEAT: I’m still an OpenGL / JOGL newbie, albeit a highly motivated one. Forgive any really obvious errors, etc…)

I was heartened to see mention of a bugfix in gluScaleImage() in RC2. I rev’d my libraries and re-built my project, but still no joy. My read is that there’s possibly a fencepost error of some sort – here’s what I know:

I get a java.nio.BufferUnderflowException inside a call to:
getGLU().gluScaleImage(format, w, h, GL.GL_UNSIGNED_BYTE, pixels, w2, h2, GL.GL_UNSIGNED_BYTE, po2Pixels);
but tweaking the code to:
getGLU().gluScaleImage(format, w, (h-1), GL.GL_UNSIGNED_BYTE, pixels, w2, h2, GL.GL_UNSIGNED_BYTE, po2Pixels);
avoids the crash, although it messes up the results visually of course. FWIW, like many others who have stubbed toes on gluScaleImage, I’m trying to scale an image to power of 2 dimensions for use as a GL texture.


At the time of the call: ` w = 461 h = 230 bytesPerPixel = 3 pixels= DirectByteBuffer with limit= 318090 h2= 128 w2= 256 po2Pixels= DirectByteBuffer with limit= 98304 `
Stack trace:

java.nio.BufferUnderflowException at java.nio.Buffer.nextGetIndex(Buffer.java:398) at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:205) at com.sun.opengl.impl.mipmap.Image.fill_image(Image.java:236) at com.sun.opengl.impl.mipmap.Mipmap.gluScaleImage(Mipmap.java:574) at javax.media.opengl.glu.GLU.gluScaleImageJava(GLU.java:1475) at javax.media.opengl.glu.GLU.gluScaleImage(GLU.java:1610) at sketches.J4$Floorplan.getTexture(J4.java:618) at sketches.J4$Floorplan.getTextureID(J4.java:646) at sketches.J4$Floorplan.draw(J4.java:684) at sketches.J4$AnimationPanel.drawStuff(J4.java:246) at sketches.J4$AnimationPanel.display(J4.java:214) at com.sun.opengl.impl.GLDrawableHelper.display(GLDrawableHelper.java:78) at javax.media.opengl.GLCanvas$DisplayAction.run(GLCanvas.java:324) at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:194) at javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:341) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199) at java.awt.EventQueue.dispatchEvent(EventQueue.java:461) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176) at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)


And the method in question:

private TextureReader.Texture getTexture() { if (_texture == null) { try { TextureReader.Texture t = TextureReader.readTexture(getFloorplanFilename()); int w = t.getWidth(); int h = t.getHeight(); int w2 = powerOfTwoFloor(w); int h2 = powerOfTwoFloor(h); if ((w == w2) && (h == h2)) { // texture is already power of two -- life is easy _texture = t; } else { // need to scale texture to a power of two ByteBuffer pixels = t.getPixels(); int bytesPerPixel = pixels.limit() / (w * h); ByteBuffer po2Pixels = BufferUtil.newByteBuffer(bytesPerPixel * w2 * h2); int format = (bytesPerPixel==4)?GL.GL_RGBA:GL.GL_RGB; try { getGLU().gluScaleImage(format, w, h, GL.GL_UNSIGNED_BYTE, pixels, w2, h2, GL.GL_UNSIGNED_BYTE, po2Pixels); } catch (RuntimeException e) { e.printStackTrace(); } _texture = new TextureReader.Texture(po2Pixels, w2, h2); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } return _texture; }

As a workaround, I believe I can scale the image using AWT / AffineTransform. But in the spirit of a good community member, I thought I’d give as much info as I could on gluScaleImage. Let me know if there’s anything else you’d like me to try.

Cheers for now,

  • fearless

See, you have some division ‘/’ code that should use float or double arguments to make a correct calculation.
This is a classical mistake… ;D

Hi broumbroum:

I apologize, but I’m not sure what division code you are referring to. If you’re referring to the line:
int bytesPerPixel = pixels.limit() / (w * h);
I absolutely do intend integer division, since pixels.limit() was originally generated by (width * height * bitsPerPixel). That might not have been clear to the casual reader and perhaps I should have commented it as such.

Of course, if you weren’t referring to that bit of code, then I am surely making a mistake and I call upon your superior intellect to lead me to enlightenment.

So just where is the problem?

Keep in mind that GL_UNPACK_ALIGNMENT is obeyed by gluScaleImage. You may find it necessary to call glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before calling gluScaleImage. The default is 4.

If that doesn’t help, then small and self-contained test case including the problematic image is necessary to make progress. In this case, please become an Observer of the JOGL project and file a bug with the Issue Tracker.

This is the way the code will do your calculation: pixels by an integer. if your pixels limit is greater than the integer there will be correct values but if the limit is smaller you’ll get a problematic Zero-value as a result. This is the case with Scaling in Java2D. Someone’s already told me about this mistake in my code, which I’ve just modified with new float values. This opened me the scaled images operations which did get systematically in error previously with Integer value to get the scale factors.
Test with (float)pixels.limit() / (float)(w*h) and you may see the difference…! :smiley:

Ken:

[quote]Keep in mind that GL_UNPACK_ALIGNMENT is obeyed by gluScaleImage. You may find it necessary to call glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before calling gluScaleImage. The default is 4.
[/quote]
You are exactly correct: setting glPixelStore(GL_UNPACK_ALIGNMENT, 1) before calling gluScaleImage() fixed the crasher I was observing. In my feeble defense, “OpenGL Programming Guide” (Schreiner, Woo, Neider, Davis) isn’t particularly illuminating on this topic – there’s no mention that alignment is important to gluScaleImage. Is there a better reference anyone would recommend?

Thanks, all.

Check out the new man pages that are part of the OpenGL SDK on opengl.org. The first sentence of the man page for gluScaleImage basically says it: “gluScaleImage scales a pixel image using the appropriate pixel store modes to unpack data from the source image and pack data into the destination image.”