Home | History | Annotate | Download | only in android
      1 package com.jme3.renderer.android;
      2 
      3 import android.graphics.Bitmap;
      4 import android.opengl.GLES20;
      5 import android.opengl.GLUtils;
      6 import com.jme3.asset.AndroidImageInfo;
      7 import com.jme3.math.FastMath;
      8 import com.jme3.texture.Image;
      9 import com.jme3.texture.Image.Format;
     10 import java.nio.ByteBuffer;
     11 import javax.microedition.khronos.opengles.GL10;
     12 
     13 public class TextureUtil {
     14 
     15     public static int convertTextureFormat(Format fmt){
     16         switch (fmt){
     17             case Alpha16:
     18             case Alpha8:
     19                 return GL10.GL_ALPHA;
     20             case Luminance8Alpha8:
     21             case Luminance16Alpha16:
     22                 return GL10.GL_LUMINANCE_ALPHA;
     23             case Luminance8:
     24             case Luminance16:
     25                 return GL10.GL_LUMINANCE;
     26             case RGB10:
     27             case RGB16:
     28             case BGR8:
     29             case RGB8:
     30             case RGB565:
     31                 return GL10.GL_RGB;
     32             case RGB5A1:
     33             case RGBA16:
     34             case RGBA8:
     35                 return GL10.GL_RGBA;
     36 
     37             case Depth:
     38                 return GLES20.GL_DEPTH_COMPONENT;
     39             case Depth16:
     40                 return GLES20.GL_DEPTH_COMPONENT16;
     41             case Depth24:
     42             case Depth32:
     43             case Depth32F:
     44                 throw new UnsupportedOperationException("Unsupported depth format: " + fmt);
     45 
     46             case DXT1A:
     47                 throw new UnsupportedOperationException("Unsupported format: " + fmt);
     48             default:
     49                 throw new UnsupportedOperationException("Unrecognized format: " + fmt);
     50         }
     51     }
     52 
     53     private static void buildMipmap(Bitmap bitmap) {
     54         int level = 0;
     55         int height = bitmap.getHeight();
     56         int width = bitmap.getWidth();
     57 
     58         while (height >= 1 || width >= 1) {
     59             //First of all, generate the texture from our bitmap and set it to the according level
     60             GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
     61 
     62             if (height == 1 || width == 1) {
     63                 break;
     64             }
     65 
     66             //Increase the mipmap level
     67             level++;
     68 
     69             height /= 2;
     70             width /= 2;
     71             Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
     72 
     73             //bitmap.recycle();
     74             bitmap = bitmap2;
     75         }
     76     }
     77 
     78     /**
     79      * <code>uploadTextureBitmap</code> uploads a native android bitmap
     80      * @param target
     81      * @param bitmap
     82      * @param generateMips
     83      * @param powerOf2
     84      */
     85     public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2)
     86     {
     87         if (!powerOf2)
     88         {
     89             int width = bitmap.getWidth();
     90             int height = bitmap.getHeight();
     91             if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height))
     92             {
     93                 // scale to power of two
     94                 width = FastMath.nearestPowerOfTwo(width);
     95                 height = FastMath.nearestPowerOfTwo(height);
     96                 Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
     97                 //bitmap.recycle();
     98                 bitmap = bitmap2;
     99             }
    100         }
    101 
    102         if (generateMips)
    103         {
    104             buildMipmap(bitmap);
    105         }
    106         else
    107         {
    108             GLUtils.texImage2D(target, 0, bitmap, 0);
    109             //bitmap.recycle();
    110         }
    111     }
    112 
    113     public static void uploadTexture(
    114                                      Image img,
    115                                      int target,
    116                                      int index,
    117                                      int border,
    118                                      boolean tdc,
    119                                      boolean generateMips,
    120                                      boolean powerOf2){
    121 
    122         if (img.getEfficentData() instanceof AndroidImageInfo){
    123             // If image was loaded from asset manager, use fast path
    124             AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData();
    125             uploadTextureBitmap(target, imageInfo.getBitmap(), generateMips, powerOf2);
    126             return;
    127         }
    128 
    129         // Otherwise upload image directly.
    130         // Prefer to only use power of 2 textures here to avoid errors.
    131 
    132         Image.Format fmt = img.getFormat();
    133         ByteBuffer data;
    134         if (index >= 0 || img.getData() != null && img.getData().size() > 0){
    135             data = img.getData(index);
    136         }else{
    137             data = null;
    138         }
    139 
    140         int width = img.getWidth();
    141         int height = img.getHeight();
    142         int depth = img.getDepth();
    143 
    144         boolean compress = false;
    145         int internalFormat = -1;
    146         int format = -1;
    147         int dataType = -1;
    148 
    149         switch (fmt){
    150             case Alpha16:
    151             case Alpha8:
    152                 format = GLES20.GL_ALPHA;
    153                 dataType = GLES20.GL_UNSIGNED_BYTE;
    154                 break;
    155             case Luminance8:
    156                 format = GLES20.GL_LUMINANCE;
    157                 dataType = GLES20.GL_UNSIGNED_BYTE;
    158                 break;
    159             case Luminance8Alpha8:
    160                 format = GLES20.GL_LUMINANCE_ALPHA;
    161                 dataType = GLES20.GL_UNSIGNED_BYTE;
    162                 break;
    163             case Luminance16Alpha16:
    164                 format = GLES20.GL_LUMINANCE_ALPHA;
    165                 dataType = GLES20.GL_UNSIGNED_BYTE;
    166                 break;
    167             case Luminance16:
    168                 format = GLES20.GL_LUMINANCE;
    169                 dataType = GLES20.GL_UNSIGNED_BYTE;
    170                 break;
    171             case RGB565:
    172                 format = GLES20.GL_RGB;
    173                 internalFormat = GLES20.GL_RGB565;
    174                 dataType = GLES20.GL_UNSIGNED_SHORT_5_6_5;
    175                 break;
    176             case ARGB4444:
    177                 format = GLES20.GL_RGBA;
    178                 dataType = GLES20.GL_UNSIGNED_SHORT_4_4_4_4;
    179                 break;
    180             case RGB10:
    181                 format = GLES20.GL_RGB;
    182                 dataType = GLES20.GL_UNSIGNED_BYTE;
    183                 break;
    184             case RGB16:
    185                 format = GLES20.GL_RGB;
    186                 dataType = GLES20.GL_UNSIGNED_BYTE;
    187                 break;
    188             case RGB5A1:
    189                 format = GLES20.GL_RGBA;
    190                 internalFormat = GLES20.GL_RGB5_A1;
    191                 dataType = GLES20.GL_UNSIGNED_SHORT_5_5_5_1;
    192                 break;
    193             case RGB8:
    194                 format = GLES20.GL_RGB;
    195                 dataType = GLES20.GL_UNSIGNED_BYTE;
    196                 break;
    197             case BGR8:
    198                 format = GLES20.GL_RGB;
    199                 dataType = GLES20.GL_UNSIGNED_BYTE;
    200                 break;
    201             case RGBA16:
    202                 format = GLES20.GL_RGBA;
    203                 internalFormat = GLES20.GL_RGBA4;
    204                 dataType = GLES20.GL_UNSIGNED_BYTE;
    205                 break;
    206             case RGBA8:
    207                 format = GLES20.GL_RGBA;
    208                 dataType = GLES20.GL_UNSIGNED_BYTE;
    209                 break;
    210             case DXT1A:
    211                 format = GLES20.GL_COMPRESSED_TEXTURE_FORMATS;
    212                 dataType = GLES20.GL_UNSIGNED_BYTE;
    213             case Depth:
    214                 format = GLES20.GL_DEPTH_COMPONENT;
    215                 dataType = GLES20.GL_UNSIGNED_BYTE;
    216                 break;
    217             case Depth16:
    218                 format = GLES20.GL_DEPTH_COMPONENT;
    219                 internalFormat = GLES20.GL_DEPTH_COMPONENT16;
    220                 dataType = GLES20.GL_UNSIGNED_BYTE;
    221                 break;
    222             case Depth24:
    223             case Depth32:
    224             case Depth32F:
    225                 throw new UnsupportedOperationException("Unsupported depth format: " + fmt);
    226             default:
    227                 throw new UnsupportedOperationException("Unrecognized format: " + fmt);
    228         }
    229 
    230         if (internalFormat == -1)
    231         {
    232             internalFormat = format;
    233         }
    234 
    235         if (data != null)
    236             GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
    237 
    238         int[] mipSizes = img.getMipMapSizes();
    239         int pos = 0;
    240         if (mipSizes == null){
    241             if (data != null)
    242                 mipSizes = new int[]{ data.capacity() };
    243             else
    244                 mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 };
    245         }
    246 
    247         // XXX: might want to change that when support
    248         // of more than paletted compressions is added..
    249         if (compress){
    250             data.clear();
    251             GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
    252                                       1 - mipSizes.length,
    253                                       format,
    254                                       width,
    255                                       height,
    256                                       0,
    257                                       data.capacity(),
    258                                       data);
    259             return;
    260         }
    261 
    262         for (int i = 0; i < mipSizes.length; i++){
    263             int mipWidth =  Math.max(1, width  >> i);
    264             int mipHeight = Math.max(1, height >> i);
    265             int mipDepth =  Math.max(1, depth  >> i);
    266 
    267             if (data != null){
    268                 data.position(pos);
    269                 data.limit(pos + mipSizes[i]);
    270             }
    271 
    272             if (compress && data != null){
    273                 GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
    274                                           i,
    275                                           format,
    276                                           mipWidth,
    277                                           mipHeight,
    278                                           0,
    279                                           data.remaining(),
    280                                           data);
    281             }else{
    282                 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
    283                                 i,
    284                                 internalFormat,
    285                                 mipWidth,
    286                                 mipHeight,
    287                                 0,
    288                                 format,
    289                                 dataType,
    290                                 data);
    291             }
    292 
    293             pos += mipSizes[i];
    294         }
    295     }
    296 
    297 }
    298