diff --git a/jme3-core/src/main/java/com/jme3/renderer/Caps.java b/jme3-core/src/main/java/com/jme3/renderer/Caps.java index 5dea0c5ec..7bda5f4ae 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Caps.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Caps.java @@ -438,10 +438,11 @@ public enum Caps { /** * Explicit support of depth 24 textures */ - Depth24; - - + Depth24, + + UnpackRowLength + ; /** * Returns true if given the renderer capabilities, the texture diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index bd3e2ea64..9f7c5ac30 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -194,6 +194,7 @@ public interface GL { public static final int GL_VERSION = 0x1F02; public static final int GL_VERTEX_SHADER = 0x8B31; public static final int GL_ZERO = 0x0; + public static final int GL_UNPACK_ROW_LENGTH = 0x0CF2; public void resetStats(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 0d9e60d14..d20c78b30 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -52,6 +52,7 @@ import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer.RenderBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; import com.jme3.texture.Texture.ShadowCompareMode; import com.jme3.texture.Texture.WrapAxis; import com.jme3.texture.image.LastTextureState; @@ -528,6 +529,10 @@ public final class GLRenderer implements Renderer { if (hasExtension("GL_OES_tessellation_shader") || hasExtension("GL_EXT_tessellation_shader")) { caps.add(Caps.TesselationShader); } + + if(caps.contains(Caps.OpenGL20)){ + caps.add(Caps.UnpackRowLength); + } // Print context information logger.log(Level.INFO, "OpenGL Renderer Information\n" + @@ -2537,12 +2542,34 @@ public final class GLRenderer implements Renderer { setupTextureParams(unit, tex); } + + /** + * @deprecated Use modifyTexture(Texture2D dest, Image src, int destX, int destY, int srcX, int srcY, int areaW, int areaH) + */ + @Deprecated public void modifyTexture(Texture tex, Image pixels, int x, int y) { setTexture(0, tex); int target = convertTextureType(tex.getType(), pixels.getMultiSamples(), -1); - texUtil.uploadSubTexture(pixels, target, 0, x, y, linearizeSrgbImages); + texUtil.uploadSubTexture(target,pixels, 0, x, y,0,0,pixels.getWidth(),pixels.getHeight(), linearizeSrgbImages); + } + + /** + * Copy a part of an image to a texture 2d. + * @param dest The destination image, where the source will be copied + * @param src The source image that contains the data to copy + * @param destX First pixel of the destination image from where the src image will be drawn (x component) + * @param destY First pixel of the destination image from where the src image will be drawn (y component) + * @param srcX First pixel to copy (x component) + * @param srcY First pixel to copy (y component) + * @param areaW Width of the area to copy + * @param areaH Height of the area to copy + */ + public void modifyTexture(Texture2D dest, Image src, int destX, int destY, int srcX, int srcY, int areaW, int areaH) { + setTexture(0, dest); + int target = convertTextureType(dest.getType(), src.getMultiSamples(), -1); + texUtil.uploadSubTexture(target, src, 0, destX, destY, srcX, srcY, areaW, areaH, linearizeSrgbImages); } - + public void deleteImage(Image image) { int texId = image.getId(); if (texId != -1) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java index 8c0d407b9..7086eb045 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java @@ -54,6 +54,7 @@ final class TextureUtil { private final GL2 gl2; private final GLExt glext; private GLImageFormat[][] formats; + private boolean supportUnpackRowLength; public TextureUtil(GL gl, GL2 gl2, GLExt glext) { this.gl = gl; @@ -62,6 +63,7 @@ final class TextureUtil { } public void initialize(EnumSet caps) { + supportUnpackRowLength = caps.contains(Caps.UnpackRowLength); this.formats = GLImageFormats.getFormatsForCaps(caps); if (logger.isLoggable(Level.FINE)) { StringBuilder sb = new StringBuilder(); @@ -298,6 +300,10 @@ final class TextureUtil { } } + /** + * @deprecated Use uploadSubTexture(int target, Image src, int index,int targetX, int targetY,int srcX,int srcY, int areaWidth,int areaHeight, boolean linearizeSrgb) + */ + @Deprecated public void uploadSubTexture(Image image, int target, int index, int x, int y, boolean linearizeSrgb) { if (target != GL.GL_TEXTURE_2D || image.getDepth() > 1) { throw new UnsupportedOperationException("Updating non-2D texture is not supported"); @@ -338,4 +344,63 @@ final class TextureUtil { gl.glTexSubImage2D(target, 0, x, y, image.getWidth(), image.getHeight(), oglFormat.format, oglFormat.dataType, data); } + + public void uploadSubTexture(int target, Image src, int index, int targetX, int targetY, int areaX, int areaY, int areaWidth, int areaHeight, boolean linearizeSrgb) { + if (target != GL.GL_TEXTURE_2D || src.getDepth() > 1) { + throw new UnsupportedOperationException("Updating non-2D texture is not supported"); + } + + if (src.getMipMapSizes() != null) { + throw new UnsupportedOperationException("Updating mip-mappped images is not supported"); + } + + if (src.getMultiSamples() > 1) { + throw new UnsupportedOperationException("Updating multisampled images is not supported"); + } + + Image.Format jmeFormat = src.getFormat(); + + if (jmeFormat.isCompressed()) { + throw new UnsupportedOperationException("Updating compressed images is not supported"); + } else if (jmeFormat.isDepthFormat()) { + throw new UnsupportedOperationException("Updating depth images is not supported"); + } + + boolean getSrgbFormat = src.getColorSpace() == ColorSpace.sRGB && linearizeSrgb; + GLImageFormat oglFormat = getImageFormatWithError(jmeFormat, getSrgbFormat); + + ByteBuffer data = src.getData(index); + + if (data == null) { + throw new IndexOutOfBoundsException("The image index " + index + " is not valid for the given image"); + } + + int Bpp = src.getFormat().getBitsPerPixel() / 8; + + int srcWidth = src.getWidth(); + int cpos = data.position(); + int skip = areaX; + skip += areaY * srcWidth; + skip *= Bpp; + + data.position(skip); + + boolean needsStride = srcWidth != areaWidth; + + if (needsStride && (!supportUnpackRowLength)) { // doesn't support stride, copy row by row (slower). + for (int i = 0; i < areaHeight; i++) { + data.position(skip + (srcWidth * Bpp * i)); + gl.glTexSubImage2D(target, 0, targetX, targetY + i, areaWidth, 1, oglFormat.format, oglFormat.dataType, data); + } + } else { + if (needsStride) + gl2.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, srcWidth); + gl.glTexSubImage2D(target, 0, targetX, targetY, areaWidth, areaHeight, oglFormat.format, oglFormat.dataType, data); + if (needsStride) + gl2.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0); + } + data.position(cpos); + + } + }