Prechádzať zdrojové kódy

Improve support for subimage copying. Allow to copy a part of an image to a texture2D.

Riccardo Balbo 5 rokov pred
rodič
commit
b07a11c9d4

+ 4 - 3
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

+ 1 - 0
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();
 

+ 29 - 2
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) {

+ 65 - 0
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> 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);
+
+    }
+
 }