blob: 4a60d6bd158798a3eb19c39f0ff6c319274cb34d [file] [log] [blame]
Scott Barta59b2e682012-03-01 12:35:35 -08001package com.jme3.renderer.android;
2
3import android.graphics.Bitmap;
4import android.opengl.GLES20;
5import android.opengl.GLUtils;
6import com.jme3.asset.AndroidImageInfo;
7import com.jme3.math.FastMath;
8import com.jme3.texture.Image;
9import com.jme3.texture.Image.Format;
10import java.nio.ByteBuffer;
11import javax.microedition.khronos.opengles.GL10;
12
13public 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
Scott Bartaa6b44652012-03-09 13:52:20 -080073 //bitmap.recycle();
Scott Barta59b2e682012-03-01 12:35:35 -080074 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);
Scott Bartaa6b44652012-03-09 13:52:20 -080097 //bitmap.recycle();
Scott Barta59b2e682012-03-01 12:35:35 -080098 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}