Browse Source

Android: added support for cube maps, Sky works now, use AndroidSkyFactory

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7531 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
kim..ng 14 years ago
parent
commit
e5478faae0

+ 78 - 73
engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -1708,50 +1708,59 @@ public class OGLESShaderRenderer implements Renderer {
         }
     }
 
-    private void setupTextureParams(Texture tex){
+    /**
+     * <code>setupTextureParams</code> sets the OpenGL context texture parameters
+     * @param tex the Texture to set the texture parameters from
+     */
+    private void setupTextureParams(Texture tex)
+    {
         int target = convertTextureType(tex.getType());
 
         // filter things
         int minFilter = convertMinFilter(tex.getMinFilter());
         int magFilter = convertMagFilter(tex.getMagFilter());
 
-	if (verboseLogging)
-		logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")");
+        if (verboseLogging)
+            logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")");
 
         GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter);
 
-	if (verboseLogging)
-		logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")");
+        if (verboseLogging)
+            logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")");
 
         GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter);
 
+        /*        
         if (tex.getAnisotropicFilter() > 1){
-/*
+
             if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){
                 glTexParameterf(target,
                                 EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT,
                                 tex.getAnisotropicFilter());
             }
-*/
+
         }
+        */        
         // repeat modes
 
         switch (tex.getType()){
             case ThreeDimensional:
             case CubeMap: // cubemaps use 3D coords
-//                GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R)));
+                // GL_TEXTURE_WRAP_R is not available in api 8
+                //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R)));
             case TwoDimensional:
             case TwoDimensionalArray:
 
-		if (verboseLogging)
-			logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T)));
+                if (verboseLogging)
+                    logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T)));
 
                 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T)));
+                
                 // fall down here is intentional..
-//            case OneDimensional:
+//          case OneDimensional:
 
-		if (verboseLogging)
-			logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S)));
+                if (verboseLogging)
+                    logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S)));
 
                 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S)));
                 break;
@@ -1773,13 +1782,20 @@ public class OGLESShaderRenderer implements Renderer {
 */
     }
 
-    public void updateTexImageData(Image img, Texture.Type type, boolean mips){
+    /**
+     * <code>updateTexImageData</code> activates and binds the texture
+     * @param img
+     * @param type
+     * @param mips
+     */
+    public void updateTexImageData(Image img, Texture.Type type, boolean mips)
+    {        
         int texId = img.getId();
-        if (texId == -1){
+        if (texId == -1)
+        {
             // create texture
-
-		if (verboseLogging)
-			logger.info("GLES20.glGenTexture(1, buffer)");
+            if (verboseLogging)
+                logger.info("GLES20.glGenTexture(1, buffer)");
 
             GLES20.glGenTextures(1, intBuf1);
             texId = intBuf1.get(0);
@@ -1791,72 +1807,56 @@ public class OGLESShaderRenderer implements Renderer {
 
         // bind texture
         int target = convertTextureType(type);
-        if (context.boundTextures[0] != img){
-            if (context.boundTextureUnit != 0){
-
-		if (verboseLogging)
-			logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)");
+        if (context.boundTextures[0] != img)
+        {
+            if (context.boundTextureUnit != 0)
+            {
+                if (verboseLogging)
+                    logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)");
 
                 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
                 context.boundTextureUnit = 0;
             }
 
-		if (verboseLogging)
-			logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")");
+            if (verboseLogging)
+                logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")");
 
             GLES20.glBindTexture(target, texId);
             context.boundTextures[0] = img;
         }
 
-        if (!img.hasMipmaps() && mips){
-            // No pregenerated mips available,
-            // generate from base level if required
-//          if (!GLContext.getCapabilities().GL_EXT_framebuffer_multisample){
-
-		if (verboseLogging)
-			logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
 
-            GLES20.glTexParameteri(target, GLES11.GL_GENERATE_MIPMAP, GLES20.GL_TRUE);
-//          }
-        }else{
-//          glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0 );
-            if (img.getMipMapSizes() != null){
-//               GLES20.glTexParameteri(target, GLES11.GL_TEXTURE_MAX_LEVEL,  img.getMipMapSizes().length );
+        if (target == GLES20.GL_TEXTURE_CUBE_MAP)
+        {
+            // Upload a cube map / sky box
+            @SuppressWarnings("unchecked")
+            List<Bitmap> bmps = (List<Bitmap>)img.getEfficentData();
+            if (bmps.size() != 6)
+            {
+                throw new UnsupportedOperationException("Invalid texture: " + img +
+                                                        "Cubemap textures must contain 6 data units." );
+            }
+            for (int i = 0; i < 6; i++)
+            {
+                TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i), false, powerOf2);                
             }
         }
+        else
+        {
+            TextureUtil.uploadTexture(img, target, 0, 0, tdc, false, powerOf2);
 
+            if (verboseLogging)
+                logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
 
-        if (target == GLES20.GL_TEXTURE_CUBE_MAP){
-            List<ByteBuffer> data = img.getData();
-            if (data.size() != 6){
-                logger.log(Level.WARNING, "Invalid texture: {0}\n"
-                        + "Cubemap textures must contain 6 data units.", img);
-                return;
-            }
-            for (int i = 0; i < 6; i++){
-                TextureUtil.uploadTexture(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, true, powerOf2);
-            }
-        }/*else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
-            List<ByteBuffer> data = img.getData();
-            // -1 index specifies prepare data for 2D Array
-            TextureUtil.uploadTexture(img, target, -1, 0, tdc);
-            for (int i = 0; i < data.size(); i++){
-                // upload each slice of 2D array in turn
-                // this time with the appropriate index
-                 TextureUtil.uploadTexture(img, target, i, 0, tdc);
+            if (!img.hasMipmaps() && mips)
+            {
+                // No pregenerated mips available,
+                // generate from base level if required
+                if (verboseLogging)
+                    logger.info("GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D)");
+                GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
             }
-        }*/else{
-            TextureUtil.uploadTexture(img, target, 0, 0, tdc, true, powerOf2);
-
-		if (verboseLogging)
-			logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
-
-		GLES20.glTexParameteri(target, GLES11.GL_GENERATE_MIPMAP, GLES20.GL_TRUE);
-        }
-            
-//            if (GLContext.getCapabilities().GL_EXT_framebuffer_multisample){
-//                glGenerateMipmapEXT(target);
-//            }
+        }            
         
         img.clearUpdateNeeded();
     }
@@ -1866,14 +1866,19 @@ public class OGLESShaderRenderer implements Renderer {
         Image image = tex.getImage();
         if (image.isUpdateNeeded())
         {
+            /*
             Bitmap bmp = (Bitmap)image.getEfficentData();
-            // Check if the bitmap got recycled, can happen after wakeup/restart
-            if ( bmp.isRecycled() )
+            if (bmp != null)
             {
-                // We need to reload the bitmap
-                Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey());
-                image.setEfficentData( textureReloaded.getImage().getEfficentData());
+                // Check if the bitmap got recycled, can happen after wakeup/restart
+                if ( bmp.isRecycled() )
+                {
+                    // We need to reload the bitmap
+                    Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey());
+                    image.setEfficentData( textureReloaded.getImage().getEfficentData());
+                }
             }
+            */
             updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels());
         }
 

+ 21 - 9
engine/src/android/com/jme3/renderer/android/TextureUtil.java

@@ -62,11 +62,21 @@ public class TextureUtil {
         }
     }
 
-    private static void uploadTextureBitmap(Bitmap bitmap, boolean generateMips, boolean powerOf2){
-        if (!powerOf2){
+    /**
+     * <code>uploadTextureBitmap</code> uploads a native android bitmap
+     * @param target
+     * @param bitmap
+     * @param generateMips
+     * @param powerOf2
+     */
+    public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2)
+    {
+        if (!powerOf2)
+        {
             int width = bitmap.getWidth();
             int height = bitmap.getHeight();
-            if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)){
+            if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height))
+            {
                 // scale to power of two
                 width = FastMath.nearestPowerOfTwo(width);
                 height = FastMath.nearestPowerOfTwo(height);
@@ -76,11 +86,14 @@ public class TextureUtil {
             }
         }
 
-        if (generateMips){
+        if (generateMips)
+        {
             buildMipmap(bitmap);
-        }else{
-            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
-            bitmap.recycle();
+        }
+        else
+        {
+            GLUtils.texImage2D(target, 0, bitmap, 0);
+            //bitmap.recycle();
         }
     }
 
@@ -95,8 +108,7 @@ public class TextureUtil {
 
         if (img.getEfficentData() instanceof Bitmap){
             Bitmap bitmap = (Bitmap) img.getEfficentData();
-            uploadTextureBitmap(bitmap, generateMips, powerOf2);
-//            img.setEfficentData(null);
+            uploadTextureBitmap(target, bitmap, generateMips, powerOf2);
             return;
         }
 

+ 148 - 0
engine/src/android/com/jme3/util/android/AndroidSkyFactory.java

@@ -0,0 +1,148 @@
+package com.jme3.util.android;
+
+import java.util.ArrayList;
+import android.graphics.Bitmap;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.TextureKey;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import com.jme3.texture.TextureCubeMap;
+
+
+/**
+ * <code>AndroidSkyFactory</code> creates a sky box spatial
+ * @author larynx, derived from SkyFactory and adapted for android
+ *
+ */
+public class AndroidSkyFactory 
+{
+    private static final Sphere sphereMesh = new Sphere(10, 10, 101f, false, true);
+
+    public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap)
+    {
+        Geometry sky = new Geometry("Sky", sphereMesh);
+        sky.setQueueBucket(Bucket.Sky);
+        sky.setCullHint(Spatial.CullHint.Never);
+
+        Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");           
+        skyMat.setVector3("NormalScale", normalScale);
+        if (sphereMap)
+        {
+            skyMat.setBoolean("SphereMap", sphereMap);
+        }
+        else if (!(texture instanceof TextureCubeMap))
+        {
+            // make sure its a cubemap
+            Image img = texture.getImage();
+            texture = new TextureCubeMap();
+            texture.setImage(img);
+        }
+        skyMat.setTexture("Texture", texture);
+        sky.setMaterial(skyMat);
+        
+        return sky;
+    }
+
+    private static void checkImage(Image image)
+    {
+        if (image.getWidth() != image.getHeight())
+            throw new IllegalArgumentException("Image width and height must be the same");
+
+        if (image.getMultiSamples() != 1)
+            throw new IllegalArgumentException("Multisample textures not allowed");
+    }
+
+    private static void checkImagesForCubeMap(Image ... images)
+    {
+        if (images.length == 1) return;
+
+        Format fmt = images[0].getFormat();
+        int width = images[0].getWidth();
+        int height = images[0].getHeight();
+
+        checkImage(images[0]);
+
+        for (int i = 1; i < images.length; i++)
+        {
+            Image image = images[i];
+            checkImage(images[i]);
+            if (image.getFormat() != fmt) throw new IllegalArgumentException("Images must have same format");
+            if (image.getWidth() != width) throw new IllegalArgumentException("Images must have same width");
+            if (image.getHeight() != height) throw new IllegalArgumentException("Images must have same height");
+        }
+    }
+
+    public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, 
+                                    Texture up, Texture down, Vector3f normalScale)
+    {
+        Geometry sky = new Geometry("Sky", sphereMesh);
+        sky.setQueueBucket(Bucket.Sky);
+        sky.setCullHint(Spatial.CullHint.Never);
+
+        Image westImg  = west.getImage();
+        Image eastImg  = east.getImage();
+        Image northImg = north.getImage();
+        Image southImg = south.getImage();
+        Image upImg    = up.getImage();
+        Image downImg  = down.getImage();
+
+        checkImagesForCubeMap(westImg, eastImg, northImg, southImg, upImg, downImg);
+
+        Image cubeImage = new Image(westImg.getFormat(), westImg.getWidth(), westImg.getHeight(), null);
+
+        ArrayList<Bitmap> arrayList = new ArrayList<Bitmap>(6);
+        
+        arrayList.add((Bitmap)westImg.getEfficentData());
+        arrayList.add((Bitmap)eastImg.getEfficentData());
+        
+        arrayList.add((Bitmap)downImg.getEfficentData());
+        arrayList.add((Bitmap)upImg.getEfficentData());
+
+        arrayList.add((Bitmap)southImg.getEfficentData());
+        arrayList.add((Bitmap)northImg.getEfficentData());
+
+        cubeImage.setEfficentData(arrayList);
+
+        TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);        
+        cubeMap.setAnisotropicFilter(0);
+        cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
+        cubeMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
+        cubeMap.setWrap(Texture.WrapMode.EdgeClamp);
+        
+        
+        Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");            
+        skyMat.setTexture("Texture", cubeMap);            
+        skyMat.setVector3("NormalScale", normalScale);
+        sky.setMaterial(skyMat);
+
+        return sky;
+    }
+
+    public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, 
+                                    Texture up, Texture down)
+    {
+        return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ);
+    }
+
+    public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap)
+    {
+        return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap);
+    }
+
+    public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap)
+    {
+        TextureKey key = new TextureKey(textureName, true);
+        key.setGenerateMips(true);
+        key.setAsCube(!sphereMap);
+        Texture tex = assetManager.loadTexture(key);
+        return createSky(assetManager, tex, sphereMap);
+    }
+}