• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
convertTextureFormat(Format fmt)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 
buildMipmap(Bitmap bitmap)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      */
uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2)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 
uploadTexture( Image img, int target, int index, int border, boolean tdc, boolean generateMips, boolean powerOf2)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