Pārlūkot izejas kodu

Added support to upload/modify sub texture to Renderer interface introducing a new method:
public void modifyTexture(Texture tex, Image pixels, int x, int y);
Implementations added for LWJGL and JOGL. LWJGL seems to work. JOGL is untestet. Android implementation needs to be done by someone else (but is already prepared for).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10462 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

voi..om 12 gadi atpakaļ
vecāks
revīzija
23c1fddf8f

+ 5 - 0
engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -1603,6 +1603,11 @@ public class OGLESShaderRenderer implements Renderer {
         setupTextureParams(tex);
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+      setTexture(0, tex);
+      TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y);
+    }
+
     public void clearTextureUnits() {
         IDList textureList = context.textureIndexList;
         Image[] textures = context.boundTextures;

+ 19 - 0
engine/src/android/com/jme3/renderer/android/TextureUtil.java

@@ -401,4 +401,23 @@ public class TextureUtil {
         }
     }
 
+    /**
+     * Update the texture currently bound to target at with data from the given Image at position x and y. The parameter
+     * index is used as the zoffset in case a 3d texture or texture 2d array is being updated.
+     *
+     * @param image Image with the source data (this data will be put into the texture)
+     * @param target the target texture
+     * @param index the mipmap level to update
+     * @param x the x position where to put the image in the texture
+     * @param y the y position where to put the image in the texture
+     */
+    public static void uploadSubTexture(
+        Image image,
+        int target,
+        int index,
+        int x,
+        int y) {
+      // FIXME and implement this!
+    }
+
 }

+ 10 - 0
engine/src/core/com/jme3/renderer/Renderer.java

@@ -238,6 +238,16 @@ public interface Renderer {
      */
     public void setTexture(int unit, Texture tex);
 
+    /**
+     * Modify the given Texture tex with the given Image. The image will be put at x and y into the texture.
+     *
+     * @param tex the Texture that will be modified
+     * @param pixels the source Image data to copy data from
+     * @param x the x position to put the image into the texture
+     * @param y the y position to put the image into the texture
+     */
+    public void modifyTexture(Texture tex, Image pixels, int x, int y);
+
     /**
      * Deletes a texture from the GPU.
      */

+ 6 - 2
engine/src/core/com/jme3/system/NullRenderer.java

@@ -31,6 +31,9 @@
  */
 package com.jme3.system;
 
+import java.nio.ByteBuffer;
+import java.util.EnumSet;
+
 import com.jme3.light.LightList;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
@@ -45,8 +48,6 @@ import com.jme3.shader.Shader.ShaderSource;
 import com.jme3.texture.FrameBuffer;
 import com.jme3.texture.Image;
 import com.jme3.texture.Texture;
-import java.nio.ByteBuffer;
-import java.util.EnumSet;
 
 public class NullRenderer implements Renderer {
 
@@ -127,6 +128,9 @@ public class NullRenderer implements Renderer {
     public void setTexture(int unit, Texture tex) {
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+    }
+
     public void updateBufferData(VertexBuffer vb) {
     }
 

+ 32 - 11
engine/src/jogl/com/jme3/renderer/jogl/JoglGL1Renderer.java

@@ -31,7 +31,33 @@
  */
 package com.jme3.renderer.jogl;
 
-import com.jme3.light.*;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.fixedfunc.GLLightingFunc;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+import javax.media.opengl.fixedfunc.GLPointerFunc;
+
+import jme3tools.converters.MipMapGenerator;
+
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
 import com.jme3.material.FixedFuncBinding;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
@@ -56,16 +82,6 @@ import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapAxis;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.NativeObjectManager;
-import java.nio.*;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.media.opengl.*;
-import javax.media.opengl.fixedfunc.GLLightingFunc;
-import javax.media.opengl.fixedfunc.GLMatrixFunc;
-import javax.media.opengl.fixedfunc.GLPointerFunc;
-import jme3tools.converters.MipMapGenerator;
 
 public class JoglGL1Renderer implements GL1Renderer {
 
@@ -886,6 +902,11 @@ public class JoglGL1Renderer implements GL1Renderer {
         setupTextureParams(tex);
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+      setTexture(0, tex);
+      TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y);
+    }
+
     private void clearTextureUnits() {
         Image[] textures = context.boundTextures;
         if (textures[0] != null) {

+ 24 - 13
engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java

@@ -31,6 +31,25 @@
  */
 package com.jme3.renderer.jogl;
 
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
+
+import jme3tools.converters.MipMapGenerator;
+import jme3tools.shader.ShaderDebug;
+
 import com.jme3.light.LightList;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
@@ -64,20 +83,7 @@ import com.jme3.util.BufferUtils;
 import com.jme3.util.ListMap;
 import com.jme3.util.NativeObjectManager;
 import com.jme3.util.SafeArrayList;
-import java.nio.*;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.media.nativewindow.NativeWindowFactory;
-import javax.media.opengl.GL;
-import javax.media.opengl.GL2;
-import javax.media.opengl.GL2ES1;
-import javax.media.opengl.GL2ES2;
-import javax.media.opengl.GL2GL3;
-import javax.media.opengl.GLContext;
-import jme3tools.converters.MipMapGenerator;
-import jme3tools.shader.ShaderDebug;
 
 public class JoglRenderer implements Renderer {
 
@@ -2043,6 +2049,11 @@ public class JoglRenderer implements Renderer {
         setupTextureParams(tex);
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+      setTexture(0, tex);
+      TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), -1), 0, x, y);
+    }
+
     public void clearTextureUnits() {
         /*GL gl = GLContext.getCurrentGL();
          IDList textureList = context.textureIndexList;

+ 95 - 3
engine/src/jogl/com/jme3/renderer/jogl/TextureUtil.java

@@ -32,16 +32,18 @@
 
 package com.jme3.renderer.jogl;
 
-import com.jme3.renderer.RendererException;
-import com.jme3.texture.Image;
-import com.jme3.texture.Image.Format;
 import java.nio.ByteBuffer;
+
 import javax.media.opengl.GL;
 import javax.media.opengl.GL2;
 import javax.media.opengl.GL2ES2;
 import javax.media.opengl.GL2GL3;
 import javax.media.opengl.GLContext;
 
+import com.jme3.renderer.RendererException;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+
 public class TextureUtil {
     
     private static boolean abgrToRgbaConversionEnabled = false;
@@ -409,4 +411,94 @@ public class TextureUtil {
         }
 
     }
+
+    /**
+     * Update the texture currently bound to target at with data from the given Image at position x and y. The parameter
+     * index is used as the zoffset in case a 3d texture or texture 2d array is being updated.
+     *
+     * @param image Image with the source data (this data will be put into the texture)
+     * @param target the target texture
+     * @param index the mipmap level to update
+     * @param x the x position where to put the image in the texture
+     * @param y the y position where to put the image in the texture
+     */
+    public static void uploadSubTexture(
+        Image image,
+        int target,
+        int index,
+        int x,
+        int y) {
+      GL gl = GLContext.getCurrentGL();
+      Image.Format fmt = image.getFormat();
+      GLImageFormat glFmt = getImageFormatWithError(fmt);
+
+      ByteBuffer data = null;
+      if (index >= 0 && image.getData() != null && image.getData().size() > 0) {
+        data = image.getData(index);
+      }
+
+      int width = image.getWidth();
+      int height = image.getHeight();
+      int depth = image.getDepth();
+
+      if (data != null) {
+        gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
+      }
+
+      int[] mipSizes = image.getMipMapSizes();
+      int pos = 0;
+
+      // TODO: Remove unneccessary allocation
+      if (mipSizes == null){
+        if (data != null) {
+          mipSizes = new int[]{ data.capacity() };
+        } else {
+          mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 };
+        }
+      }
+
+      int samples = image.getMultiSamples();
+
+      for (int i = 0; i < mipSizes.length; i++){
+        int mipWidth =  Math.max(1, width  >> i);
+        int mipHeight = Math.max(1, height >> i);
+        int mipDepth =  Math.max(1, depth  >> i);
+
+        if (data != null){
+          data.position(pos);
+          data.limit(pos + mipSizes[i]);
+        }
+
+        // to remove the cumbersome if/then/else stuff below we'll update the pos right here and use continue after each
+        // gl*Image call in an attempt to unclutter things a bit
+        pos += mipSizes[i];
+
+        int glFmtInternal = glFmt.internalFormat;
+        int glFmtFormat = glFmt.format;
+        int glFmtDataType = glFmt.dataType;
+
+        if (glFmt.compressed && data != null){
+          if (target == GL2ES2.GL_TEXTURE_3D){
+            gl.getGL2ES2().glCompressedTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtInternal, data.limit(), data);
+            continue;
+          }
+
+          // all other targets use 2D: array, cubemap, 2d
+          gl.getGL2ES2().glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtInternal, data.limit(), data);
+          continue;
+        }
+
+        if (target == GL2ES2.GL_TEXTURE_3D){
+          gl.getGL2ES2().glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data);
+          continue;
+        }
+
+        if (samples > 1){
+          throw new IllegalStateException("Cannot update multisample textures");
+        }
+
+        gl.glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtFormat, glFmtDataType, data);
+        continue;
+      }
+    }
 }

+ 28 - 11
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java

@@ -1,6 +1,28 @@
 package com.jme3.renderer.lwjgl;
 
-import com.jme3.light.*;
+import static org.lwjgl.opengl.GL11.*;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import jme3tools.converters.MipMapGenerator;
+
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GLContext;
+
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
 import com.jme3.material.FixedFuncBinding;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
@@ -25,16 +47,6 @@ import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapAxis;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.NativeObjectManager;
-import java.nio.*;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import jme3tools.converters.MipMapGenerator;
-import static org.lwjgl.opengl.GL11.*;
-import org.lwjgl.opengl.GL12;
-import org.lwjgl.opengl.GL14;
-import org.lwjgl.opengl.GLContext;
 
 public class LwjglGL1Renderer implements GL1Renderer {
 
@@ -836,6 +848,11 @@ public class LwjglGL1Renderer implements GL1Renderer {
         setupTextureParams(tex);
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+      setTexture(0, tex);
+      TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y);
+    }
+
     private void clearTextureUnits() {
         Image[] textures = context.boundTextures;
         if (textures[0] != null) {

+ 5 - 0
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -1946,6 +1946,11 @@ public class LwjglRenderer implements Renderer {
         setupTextureParams(tex);
     }
 
+    public void modifyTexture(Texture tex, Image pixels, int x, int y) {
+      setTexture(0, tex);
+      TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType(), pixels.getMultiSamples(), -1), 0, x, y);
+    }
+
     public void clearTextureUnits() {
 //        IDList textureList = context.textureIndexList;
 //        Image[] textures = context.boundTextures;

+ 119 - 2
engine/src/lwjgl/com/jme3/renderer/lwjgl/TextureUtil.java

@@ -32,11 +32,29 @@
 
 package com.jme3.renderer.lwjgl;
 
+import java.nio.ByteBuffer;
+
+import org.lwjgl.opengl.ARBHalfFloatPixel;
+import org.lwjgl.opengl.ARBTextureFloat;
+import org.lwjgl.opengl.ARBTextureMultisample;
+import org.lwjgl.opengl.ContextCapabilities;
+import org.lwjgl.opengl.EXTAbgr;
+import org.lwjgl.opengl.EXTBgra;
+import org.lwjgl.opengl.EXTPackedFloat;
+import org.lwjgl.opengl.EXTTextureArray;
+import org.lwjgl.opengl.EXTTextureCompressionLATC;
+import org.lwjgl.opengl.EXTTextureCompressionS3TC;
+import org.lwjgl.opengl.EXTTextureSharedExponent;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL13;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GL30;
+import org.lwjgl.opengl.GLContext;
+
 import com.jme3.renderer.RendererException;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
-import java.nio.ByteBuffer;
-import org.lwjgl.opengl.*;
 
 class TextureUtil {
 
@@ -349,4 +367,103 @@ class TextureUtil {
         }
     }
 
+    /**
+     * Update the texture currently bound to target at with data from the given Image at position x and y. The parameter
+     * index is used as the zoffset in case a 3d texture or texture 2d array is being updated.
+     *
+     * @param image Image with the source data (this data will be put into the texture)
+     * @param target the target texture
+     * @param index the mipmap level to update
+     * @param x the x position where to put the image in the texture
+     * @param y the y position where to put the image in the texture
+     */
+    public static void uploadSubTexture(
+        Image image,
+        int target,
+        int index,
+        int x,
+        int y) {
+      Image.Format fmt = image.getFormat();
+      GLImageFormat glFmt = getImageFormatWithError(fmt);
+
+      ByteBuffer data = null;
+      if (index >= 0 && image.getData() != null && image.getData().size() > 0) {
+        data = image.getData(index);
+      }
+
+      int width = image.getWidth();
+      int height = image.getHeight();
+      int depth = image.getDepth();
+
+      if (data != null) {
+        GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
+      }
+
+      int[] mipSizes = image.getMipMapSizes();
+      int pos = 0;
+
+      // TODO: Remove unneccessary allocation
+      if (mipSizes == null){
+        if (data != null) {
+          mipSizes = new int[]{ data.capacity() };
+        } else {
+          mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 };
+        }
+      }
+
+      int samples = image.getMultiSamples();
+
+      for (int i = 0; i < mipSizes.length; i++){
+        int mipWidth =  Math.max(1, width  >> i);
+        int mipHeight = Math.max(1, height >> i);
+        int mipDepth =  Math.max(1, depth  >> i);
+
+        if (data != null){
+          data.position(pos);
+          data.limit(pos + mipSizes[i]);
+        }
+
+        // to remove the cumbersome if/then/else stuff below we'll update the pos right here and use continue after each
+        // gl*Image call in an attempt to unclutter things a bit
+        pos += mipSizes[i];
+
+        int glFmtInternal = glFmt.internalFormat;
+        int glFmtFormat = glFmt.format;
+        int glFmtDataType = glFmt.dataType;
+
+        if (glFmt.compressed && data != null){
+          if (target == GL12.GL_TEXTURE_3D){
+            GL13.glCompressedTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtInternal, data);
+            continue;
+          }
+
+          // all other targets use 2D: array, cubemap, 2d
+          GL13.glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtInternal, data);
+          continue;
+        }
+
+        if (target == GL12.GL_TEXTURE_3D){
+          GL12.glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data);
+          continue;
+        }
+
+        if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
+          // prepare data for 2D array or upload slice
+          if (index == -1){
+            GL12.glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data);
+            continue;
+          }
+
+          GL12.glTexSubImage3D(target, i, x, y, index, width, height, 1, glFmtFormat, glFmtDataType, data);
+          continue;
+        }
+
+        if (samples > 1){
+          throw new IllegalStateException("Cannot update multisample textures");
+        }
+
+        GL11.glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtFormat, glFmtDataType, data);
+        continue;
+      }
+    }
 }