I learned from Momoko_Fan about a class called "LWJGLTextureUpdater" that efficiently sends updated image data to the graphics card after a texture has already been bound. Unfortunately, I soon learned that this class is not in jme 1.0, and I am still using jme 1.0 for my project, so I created a port of it for jme 1.0. Jme 1.0 has far fewer image formats than 2.0, particularly support for 8-bit alpha maps, so there are many formats from 2.0 commented out here. Here it is…
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.opengl.EXTTextureCompressionS3TC;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.OpenGLException;
import org.lwjgl.opengl.Util;
import com.jme.image.Texture;
import com.jme.util.geom.BufferUtils;
import static com.jme.image.Image.*;
/**
* @author Anubis
*/
public class LWJGLTextureUpdater {
private static IntBuffer idBuff = BufferUtils.createIntBuffer(16);
private static boolean glTexSubImage2DSupported = true;
/**
* Efficiently sends the updated image data to the graphics card.
*
* @param texture the <code>Texture</code>
* @param data the image data
* @param w the image width
* @param h the image height
* @param format the image format in <code>com.jme.image.Image</code>
*/
public static void updateTexture(Texture texture, ByteBuffer data, int w, int h, int format) {
int dataFormat = getGLDataFormat(format);
int pixelFormat = getGLPixelFormat(format);
idBuff.clear();
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D, idBuff);
int oldTex = idBuff.get();
GL11.glBindTexture( GL11.GL_TEXTURE_2D, texture.getTextureId() );
GL11.glPixelStorei( GL11.GL_UNPACK_ALIGNMENT, 1 );
if (glTexSubImage2DSupported) {
GL11.glTexSubImage2D( GL11.GL_TEXTURE_2D, 0,
0, 0, w, h, pixelFormat,
GL11.GL_UNSIGNED_BYTE, data );
try {
Util.checkGLError();
} catch ( OpenGLException e ) {
glTexSubImage2DSupported = false;
updateTexture(texture, data, w, h, format);
}
} else {
GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0,
dataFormat, w,
h, 0, pixelFormat,
GL11.GL_UNSIGNED_BYTE, data );
}
GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex);
}
// converted from jme 2.0 com.jme.scene.state.lwjgl.records.TextureStateRecord
private static int getGLDataFormat(int format) {
switch (format) {
// first some frequently used formats
case RGBA8888:
return GL11.GL_RGBA8;
case RGB888:
return GL11.GL_RGB8;
// case Alpha8:
// return GL11.GL_ALPHA8;
case RGB888_DXT1:
case DXT1_NATIVE:
return EXTTextureCompressionS3TC.GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
//case RGBA_TO_DXT1:
case RGBA8888_DXT1A:
case DXT1A_NATIVE:
return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case RGBA8888_DXT3:
case DXT3_NATIVE:
return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case RGBA8888_DXT5:
case DXT5_NATIVE:
return EXTTextureCompressionS3TC.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
// The rest...
/*
case Alpha4:
return GL11.GL_ALPHA4;
case Alpha12:
return GL11.GL_ALPHA12;
case Alpha16:
return GL11.GL_ALPHA16;
case Luminance4:
return GL11.GL_LUMINANCE4;
case Luminance8:
return GL11.GL_LUMINANCE8;
case Luminance12:
return GL11.GL_LUMINANCE12;
case Luminance16:
return GL11.GL_LUMINANCE16;
case Intensity4:
return GL11.GL_INTENSITY4;
case Intensity8:
return GL11.GL_INTENSITY8;
case Intensity12:
return GL11.GL_INTENSITY12;
case Intensity16:
return GL11.GL_INTENSITY16;
case Luminance4Alpha4:
return GL11.GL_LUMINANCE4_ALPHA4;
case Luminance6Alpha2:
return GL11.GL_LUMINANCE6_ALPHA2;
case Luminance8Alpha8:
return GL11.GL_LUMINANCE8_ALPHA8;
case Luminance12Alpha4:
return GL11.GL_LUMINANCE12_ALPHA4;
case Luminance12Alpha12:
return GL11.GL_LUMINANCE12_ALPHA12;
case Luminance16Alpha16:
return GL11.GL_LUMINANCE16_ALPHA16;
case R3G3B2:
return GL11.GL_R3_G3_B2;
case RGB4:
return GL11.GL_RGB4;
case RGB5:
return GL11.GL_RGB5;
case RGB10:
return GL11.GL_RGB10;
case RGB12:
return GL11.GL_RGB12;
case RGB16:
return GL11.GL_RGB16;
case RGBA2:
return GL11.GL_RGBA2;
case RGBA4:
return GL11.GL_RGBA4;
case RGB5A1:
return GL11.GL_RGB5_A1;
case RGB10A2:
return GL11.GL_RGB10_A2;
case RGBA12:
return GL11.GL_RGBA12;
case RGBA16:
return GL11.GL_RGBA16;
case Depth16:
return ARBDepthTexture.GL_DEPTH_COMPONENT16_ARB;
case Depth24:
return ARBDepthTexture.GL_DEPTH_COMPONENT24_ARB;
case Depth32:
return ARBDepthTexture.GL_DEPTH_COMPONENT32_ARB;
case RGB16F:
return ARBTextureFloat.GL_RGB16F_ARB;
case RGB32F:
return ARBTextureFloat.GL_RGB32F_ARB;
case RGBA16F:
return ARBTextureFloat.GL_RGBA16F_ARB;
case RGBA32F:
return ARBTextureFloat.GL_RGBA32F_ARB;
case Alpha16F:
return ARBTextureFloat.GL_ALPHA16F_ARB;
case Alpha32F:
return ARBTextureFloat.GL_ALPHA32F_ARB;
case Luminance16F:
return ARBTextureFloat.GL_LUMINANCE16F_ARB;
case Luminance32F:
return ARBTextureFloat.GL_LUMINANCE32F_ARB;
case LuminanceAlpha16F:
return ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
case LuminanceAlpha32F:
return ARBTextureFloat.GL_LUMINANCE_ALPHA32F_ARB;
case Intensity16F:
return ARBTextureFloat.GL_INTENSITY16F_ARB;
case Intensity32F:
return ARBTextureFloat.GL_INTENSITY32F_ARB;
*/
}
throw new IllegalArgumentException("Incorrect format set: "+format);
}
// converted from jme 2.0 com.jme.scene.state.lwjgl.records.TextureStateRecord
private static int getGLPixelFormat(int format) {
switch (format) {
case RA88:
case RGBA4444:
case RGBA8888:
case RGBA5551:
/*
case RGB10A2:
case RGBA12:
case RGBA16:
case RGBA_TO_DXT1:
case NativeDXT1A:
case RGBA_TO_DXT3:
case NativeDXT3:
case RGBA_TO_DXT5:
case NativeDXT5:
case RGBA16F:
case RGBA32F:
*/
return GL11.GL_RGBA;
case RGB888:
/*
case RGB4:
case RGB5:
case RGB8:
case RGB10:
case RGB12:
case RGB16:
case RGB_TO_DXT1:
case NativeDXT1:
case RGB16F:
case RGB32F:
*/
return GL11.GL_RGB;
/*
case Alpha4:
case Alpha8:
case Alpha12:
case Alpha16:
case Alpha16F:
case Alpha32F:
return GL11.GL_ALPHA;
case Luminance4:
case Luminance8:
case Luminance12:
case Luminance16:
case Luminance16F:
case Luminance32F:
return GL11.GL_LUMINANCE;
case Intensity4:
case Intensity8:
case Intensity12:
case Intensity16:
case Intensity16F:
case Intensity32F:
return GL11.GL_INTENSITY;
case Luminance4Alpha4:
case Luminance6Alpha2:
case Luminance8Alpha8:
case Luminance12Alpha4:
case Luminance12Alpha12:
case Luminance16Alpha16:
case LuminanceAlpha16F:
case LuminanceAlpha32F:
return GL11.GL_LUMINANCE_ALPHA;
case Depth16:
case Depth24:
case Depth32:
return GL11.GL_DEPTH_COMPONENT;
*/
}
throw new IllegalArgumentException("Incorrect format set: "+format);
}
}