There is currently no elegant way to update a sub-portion of an OpenGL texture in the JOGL API (you can only update the texture with a full BufferedImage positioned at (x,y) without being able to provide a custom width and height).

As I’m trying to render Swing components inside a 3D environment (a la Looking Glass but in much, much less ambitious :-D), I needed such a functionality…

I compared 3 update methods (update full image, update line by line or filling a reusable direct buffer with the sub-image data before setting it with a single glTexSubImage2D call), and found that the update-line-by-line method was faster on my machine (PowerBook G4, Mac OS X 10.4.8, NVIDIA 5200 something with 1.2 GB RAM), for sub-images reasonably smaller than the original (haven’t tested after which sub-size this becomes more costly than the whole texture update method, though).

Here’s a public-domain code snippet that does the job (copy-paste friendly, no warranty):

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
import java.nio.IntBuffer;
import javax.media.opengl.GL;
import com.sun.opengl.util.texture.Texture;
...
/**
 * Update a portion of a texture beginning at a given offset,
 * using a BufferedImage.
 * The provided BufferedImage can be a sub-image created with
 * BufferedImage.getSubImage(int,int,int,int),
 * in which case the (x,y) start point and the dimension of the sub-image
 * will be honoured.
 *
 * Example:
 * 	updateSubTexture(gl, texture, xTexture, yTexture,
 *   image.getSubImage(xImage, yImage, width, height));
 *
 * @see BufferedImage.getSubimage(int,int,int,int)
 * @param gl
 * @param texture
 * @param x X coordinate of subtexture
 * @param y Y coordinate of subtexture
 * @param sourceImage image to update the subtexture with.
 * @throws IllegalArgumentException if the image type is different
 *              from TYPE_INT_ARGB
 */
public void updateSubTexture(
		GL gl,
		Texture texture, int x, int y,
		BufferedImage sourceImage)
{
	if (sourceImage.getType() != BufferedImage.TYPE_INT_ARGB)
		throw new IllegalArgumentException(
			"Cannot update subtexture with anything else "+
			"than TYPE_INT_ARGB buffered images yet !");
	WritableRaster raster = sourceImage.getRaster();
	IntBuffer dataBuffer = IntBuffer.wrap(
		((DataBufferInt)raster.getDataBuffer()).getData());
	Rectangle bounds = raster.getBounds();
	// Get the scanline of the array that backs all the writable rasters
	// from this raster's hierarchy.
	// Also absolutize bounds.x and bounds.y
	int scanline = bounds.width;
	while ((raster = raster.getWritableParent()) != null) {
		Rectangle parentBounds = raster.getBounds();
		bounds.x += parentBounds.x;
		bounds.y += parentBounds.y;
		scanline = parentBounds.width;
	}
	// Update the sub texture row by row
	// not tested yet on little endian platforms : feedback welcome
	int type = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ?
		GL.GL_UNSIGNED_INT_8_8_8_8_REV :
		GL.GL_UNSIGNED_INT_8_8_8_8;
	texture.bind();
	for (int row = bounds.height; row-- != 0;) {
		dataBuffer.position((row + bounds.y) * scanline + bounds.x);
		gl.glTexSubImage2D(texture.getTarget(),
			0, // no support for mipmapping
			x, y + row, // in texture
			bounds.width, 1,
			GL.GL_BGRA,
			type,
			dataBuffer
		);
	}
	gl.glBindTexture(texture.getTarget(), 0);
}

If colours are messed up on Intel / little endian platforms, please tell me, as I haven’t tested on anything else than on my Mac/PPC laptop…

[Edit Dec. 19th 2006] : In a RFE submitted to the JOGL project, Chris Campbell referred to this entry and proposed a far better approach than the one I used : it relies on GL_PACK_ROW_LENGTH, GL_PACK_SKIP_ROWS and GL_PACK_SKIP_PIXELS. I haven’t tested it yet but it definitely seems like there won’t be any better solution. I encourage you to vote for this RFE, if you’re on the project’s watch-list…