|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 #include "javax_microedition_m3g_Image2D.h" |
|
18 |
|
19 JNIEXPORT void JNICALL Java_javax_microedition_m3g_Image2D__1set |
|
20 (JNIEnv* aEnv, jclass, jint aHImage2D, jint aX, jint aY, jint aWidth, jint aHeight, jbyteArray aImageArray) |
|
21 { |
|
22 jbyte* imageArray = NULL; |
|
23 if (aImageArray) |
|
24 { |
|
25 imageArray = aEnv->GetByteArrayElements(aImageArray, NULL); |
|
26 if (imageArray == NULL) |
|
27 { |
|
28 M3G_RAISE_EXCEPTION(aEnv, "java/lang/OutOfMemoryError"); |
|
29 return; |
|
30 } |
|
31 } |
|
32 M3G_DO_LOCK |
|
33 m3gSetSubImage((M3GImage)aHImage2D, aX, aY, aWidth, aHeight, aImageArray ? aEnv->GetArrayLength(aImageArray) : NULL, imageArray); |
|
34 M3G_DO_UNLOCK(aEnv) |
|
35 |
|
36 if (imageArray) |
|
37 { |
|
38 aEnv->ReleaseByteArrayElements(aImageArray, imageArray, JNI_ABORT); |
|
39 } |
|
40 } |
|
41 |
|
42 static void getImageScanline(const ImageStruct *pImg, |
|
43 M3Gint line, |
|
44 M3Guint *pixels, |
|
45 M3Gbool *trueAlpha) |
|
46 { |
|
47 const CFbsBitmap *bitmap = pImg->color; |
|
48 const int width = bitmap->SizeInPixels().iWidth; |
|
49 int count = width; |
|
50 M3G_ASSERT(count >= 0); |
|
51 |
|
52 M3Guint *dst = pixels; |
|
53 |
|
54 TDisplayMode mode = bitmap->DisplayMode(); |
|
55 int stride = bitmap->ScanLineLength(count, mode); |
|
56 bitmap->LockHeap(); |
|
57 const void *srcAddr = ((const char *) bitmap->DataAddress()) + line * stride; |
|
58 |
|
59 const CFbsBitmap *mask = pImg->mask; |
|
60 |
|
61 // Alpha data is stored in a separate bitmap if present, so first |
|
62 // just copy the RGB image data with a default full alpha |
|
63 |
|
64 if (mode == EColor16MU || mode == EColor16MA) |
|
65 { |
|
66 const unsigned char *src = (const unsigned char *) srcAddr; |
|
67 while (count--) |
|
68 { |
|
69 M3Guint argb; |
|
70 argb = (M3Guint)(*src++); // red -- "src" is a _byte_ pointer to the FbsBitmap's DataAddress |
|
71 argb |= ((M3Guint)(*src++)) << 8; // green |
|
72 argb |= ((M3Guint)(*src++)) << 16; // blue |
|
73 if (mask) |
|
74 { |
|
75 // if separate alpha bitmap is present, set full alpha and alpha informations |
|
76 // will be copied in second pass |
|
77 argb |= 0xFF000000L; // alpha |
|
78 } |
|
79 else |
|
80 { |
|
81 // if separate alpha is NULL alpha information must be copied from alpha channel |
|
82 // of source bitmap to alpha channel of target bitmap |
|
83 argb |= ((M3Guint)(*src)) << 24; // alpha |
|
84 } |
|
85 src++; |
|
86 *dst++ = argb; |
|
87 } |
|
88 } |
|
89 else if (mode == EColor64K) |
|
90 { |
|
91 const unsigned short *src = (const unsigned short *) srcAddr; |
|
92 while (count--) |
|
93 { |
|
94 unsigned short pixel = *src++; |
|
95 *dst++ = 0xFF000000L |
|
96 | (((pixel & 0x001F) >> 2) | ((pixel & 0x001F) << 3)) |
|
97 | (((pixel & 0x0600) >> 1) | ((pixel & 0x07E0) << 5)) |
|
98 | (((pixel & 0xE000) << 3) | ((pixel & 0xF800) << 8)); |
|
99 } |
|
100 } |
|
101 else if (mode == EColor4K) |
|
102 { |
|
103 const unsigned short *src = (const unsigned short *) srcAddr; |
|
104 while (count--) |
|
105 { |
|
106 unsigned short pixel = *src++; |
|
107 *dst++ = 0xFF000000L |
|
108 | ((pixel & 0x000F) | ((pixel & 0x000F) << 4)) |
|
109 | (((pixel & 0x00F0) | ((pixel & 0x00F0) << 4)) << 4) |
|
110 | (((pixel & 0x0F00) | ((pixel & 0x0F00) << 4)) << 8); |
|
111 } |
|
112 } |
|
113 else |
|
114 { |
|
115 M3G_ASSERT(M3G_FALSE); |
|
116 } |
|
117 bitmap->UnlockHeap(); |
|
118 |
|
119 // Check for the presence of an alpha mask, and if present, do a |
|
120 // second pass to mix that into the RGB values already copied |
|
121 |
|
122 *trueAlpha = (mask != NULL); |
|
123 |
|
124 if (mask) |
|
125 { |
|
126 |
|
127 mask->LockHeap(); |
|
128 |
|
129 // NOTE: we assume that if the alpha mask is using an RGBA |
|
130 // display mode as the base bitmap, the alpha value is stored |
|
131 // in the red color channel of the mask only. |
|
132 // |
|
133 |
|
134 dst = pixels; |
|
135 count = width; |
|
136 |
|
137 mode = mask->DisplayMode(); |
|
138 stride = mask->ScanLineLength(mask->SizeInPixels().iWidth, mode); |
|
139 srcAddr = ((const char *) mask->DataAddress()) + line * stride; |
|
140 |
|
141 if (mode == EColor16MU || mode == EColor16MA) |
|
142 { |
|
143 const unsigned long *src = (const unsigned long *) srcAddr; |
|
144 while (count--) |
|
145 { |
|
146 unsigned short mask = *src++; |
|
147 *dst++ = (*dst & 0x00FFFFFF) | ((mask & 0x00FF) << 24); |
|
148 } |
|
149 } |
|
150 else if (mode == EColor64K) |
|
151 { |
|
152 const unsigned short *src = (const unsigned short *) srcAddr; |
|
153 while (count--) |
|
154 { |
|
155 unsigned short mask = *src++; |
|
156 *dst++ = (*dst & 0x00FFFFFF) | |
|
157 ((((mask & 0x001F) >> 2) | ((mask & 0x001F) << 3)) << 24); |
|
158 } |
|
159 } |
|
160 else if (mode == EColor4K) |
|
161 { |
|
162 const unsigned short *src = (const unsigned short *) srcAddr; |
|
163 while (count--) |
|
164 { |
|
165 unsigned short mask = *src++; |
|
166 *dst++ = (*dst & 0x00FFFFFF) | (((mask & 0x000F) | ((mask & 0x000F) << 4)) << 24); |
|
167 } |
|
168 } |
|
169 else if (mode == EGray256) |
|
170 { |
|
171 const unsigned char *src = (const unsigned char *) srcAddr; |
|
172 while (count--) |
|
173 { |
|
174 *dst++ = (*dst & 0x00FFFFFF) | ((*src++) << 24); |
|
175 } |
|
176 } |
|
177 else if (mode == EGray2) |
|
178 { |
|
179 |
|
180 // Initialize src as byte type |
|
181 const unsigned char *src = (const unsigned char *) srcAddr; |
|
182 |
|
183 /* Go through each pixel in the stride one by one. |
|
184 / Each src (EGray2 type bitmap) byte holds 8 pixels aplha mask, i.e 1 Bpp, |
|
185 / so check each bit in the byte and set aplha for the dst bitmap either to 0xFF |
|
186 / or to 0x00 depending source bit values 1/0. |
|
187 */ |
|
188 |
|
189 /* Counter for the bits in one byte, i.e. 0-7 */ |
|
190 int bit = 0; |
|
191 |
|
192 /* count = number of pixels in one stride */ |
|
193 while (count) |
|
194 { |
|
195 while (bit < 8) |
|
196 { |
|
197 *dst++ = (*dst & 0x00FFFFFF) | (((*src) & 0x01 << bit) ? 0xFF << 24 : 0x0); |
|
198 bit++; |
|
199 count--; |
|
200 |
|
201 /* If we have processed all pixels in the image scanline, |
|
202 / exit and discard rest of the bits in the byte. |
|
203 */ |
|
204 |
|
205 if (count <= 0) break; |
|
206 } |
|
207 /* reset bit counter as we move on to the next byte */ |
|
208 bit = 0; |
|
209 *src++; |
|
210 } |
|
211 } |
|
212 else |
|
213 { |
|
214 M3G_ASSERT(M3G_FALSE); |
|
215 } |
|
216 mask->UnlockHeap(); |
|
217 } |
|
218 } |
|
219 |
|
220 static void createImage(M3GInterface m3g, |
|
221 M3GImage *img, |
|
222 M3GImageFormat format, |
|
223 ImageStruct *pImage) |
|
224 { |
|
225 M3GImage image; |
|
226 |
|
227 TSize sz = pImage->color->SizeInPixels(); |
|
228 M3Gint width = sz.iWidth, height = sz.iHeight; |
|
229 |
|
230 image = m3gCreateImage(m3g, format, width, height, 0); |
|
231 if (image == NULL) |
|
232 { |
|
233 img = NULL; |
|
234 return; // exception automatically raised |
|
235 } |
|
236 |
|
237 { |
|
238 M3Gint y; |
|
239 |
|
240 //M3Guint *tempPixels = (M3Guint *) User::Alloc(width * 4); |
|
241 M3Guint *tempPixels = (M3Guint *) malloc(width * 4); |
|
242 if (tempPixels == NULL) |
|
243 { |
|
244 m3gDeleteObject((M3GObject) image); |
|
245 *img = NULL; |
|
246 return; |
|
247 } |
|
248 |
|
249 for (y = 0; y < height; ++y) |
|
250 { |
|
251 M3Gbool trueAlpha; |
|
252 getImageScanline(pImage, y, tempPixels, &trueAlpha); |
|
253 m3gSetImageScanline(image, y, trueAlpha, tempPixels); |
|
254 } |
|
255 m3gCommitImage(image); |
|
256 |
|
257 //User::Free(tempPixels); |
|
258 free(tempPixels); |
|
259 *img = image; |
|
260 } |
|
261 } |
|
262 |
|
263 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1ctorImage |
|
264 (JNIEnv* aEnv, jclass, jint aEventSourceHandle, jint aHM3g, jint aFormat, jint aImageHandle) |
|
265 { |
|
266 if (aImageHandle != NULL) |
|
267 { |
|
268 ImageStruct imageStruct; |
|
269 MMIDImage* image = JavaUnhand<MMIDImage>(aImageHandle); |
|
270 MMIDBitmapImage* bitmapImage = image->BitmapImage(); |
|
271 if (!bitmapImage) |
|
272 { |
|
273 return NULL; |
|
274 } |
|
275 imageStruct.color = bitmapImage->ColorBitmap(); |
|
276 imageStruct.mask = bitmapImage->AlphaBitmap(); |
|
277 bitmapImage->RemoveRef(); |
|
278 |
|
279 CJavaM3GEventSource* eventSource = JavaUnhand<CJavaM3GEventSource>(aEventSourceHandle); |
|
280 M3GInterface m3g = (M3GInterface)aHM3g; |
|
281 |
|
282 M3GImage img; |
|
283 |
|
284 M3G_DO_LOCK |
|
285 eventSource->ExecuteV(&createImage, |
|
286 m3g, &img, (M3GImageFormat) aFormat, &imageStruct); |
|
287 M3G_DO_UNLOCK(aEnv) |
|
288 |
|
289 return (jint)img; |
|
290 } |
|
291 |
|
292 return 0; |
|
293 } |
|
294 |
|
295 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1getFormat |
|
296 (JNIEnv* aEnv, jclass, jint aHImage2D) |
|
297 { |
|
298 M3G_DO_LOCK |
|
299 jint format = (jint)m3gGetFormat((M3GImage)aHImage2D); |
|
300 M3G_DO_UNLOCK(aEnv) |
|
301 return format; |
|
302 } |
|
303 |
|
304 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1ctorSizePixelsPalette |
|
305 (JNIEnv* aEnv, jclass, jint aM3g, jint aFormat, jint aWidth, jint aHeight, jbyteArray aImage, jbyteArray aPalette) |
|
306 { |
|
307 M3GImageFormat format = (M3GImageFormat)aFormat; |
|
308 |
|
309 int bpp = jsr184BytesPerPixel(format); |
|
310 |
|
311 if (validateArray(aEnv, aImage, aWidth * aHeight)) |
|
312 { |
|
313 if (aPalette == NULL) |
|
314 { |
|
315 M3G_RAISE_EXCEPTION(aEnv, "java/lang/NullPointerException"); |
|
316 return 0; |
|
317 } |
|
318 int paletteLen = aEnv->GetArrayLength(aPalette); |
|
319 if ((paletteLen < 256 *(unsigned)bpp) && |
|
320 (paletteLen % (unsigned)bpp != 0)) |
|
321 { |
|
322 M3G_RAISE_EXCEPTION(aEnv, "java/lang/IllegalArgumentException"); |
|
323 return 0; |
|
324 } |
|
325 else |
|
326 { |
|
327 M3G_DO_LOCK |
|
328 |
|
329 M3GImage hImg = m3gCreateImage((M3GInterface)aM3g, |
|
330 format, |
|
331 aWidth, aHeight, |
|
332 M3G_PALETTED); |
|
333 if (hImg != NULL) |
|
334 { |
|
335 jbyte* palette = NULL; |
|
336 |
|
337 int numEntries = paletteLen / bpp; |
|
338 if (numEntries > 256) |
|
339 { |
|
340 numEntries = 256; |
|
341 } |
|
342 |
|
343 jbyte* image = aEnv->GetByteArrayElements(aImage, NULL); |
|
344 if (image == NULL) |
|
345 { |
|
346 M3G_RAISE_EXCEPTION(aEnv, "java/lang/OutOfMemoryError"); |
|
347 return 0; |
|
348 } |
|
349 |
|
350 m3gSetImage(hImg, image); |
|
351 |
|
352 palette = aEnv->GetByteArrayElements(aPalette, NULL); |
|
353 if (palette == NULL) |
|
354 { |
|
355 if (image) |
|
356 { |
|
357 aEnv->ReleaseByteArrayElements(aImage, image, JNI_ABORT); |
|
358 } |
|
359 M3G_RAISE_EXCEPTION(aEnv, "java/lang/OutOfMemoryError"); |
|
360 return 0; |
|
361 } |
|
362 |
|
363 m3gSetImagePalette(hImg, numEntries, palette); |
|
364 m3gCommitImage(hImg); |
|
365 |
|
366 if (image) |
|
367 { |
|
368 aEnv->ReleaseByteArrayElements(aImage, image, JNI_ABORT); |
|
369 } |
|
370 if (palette) |
|
371 { |
|
372 aEnv->ReleaseByteArrayElements(aPalette, palette, JNI_ABORT); |
|
373 } |
|
374 } |
|
375 M3G_DO_UNLOCK(aEnv) |
|
376 return ((unsigned) hImg); |
|
377 } |
|
378 } |
|
379 return 0; |
|
380 } |
|
381 |
|
382 JNIEXPORT jboolean JNICALL Java_javax_microedition_m3g_Image2D__1isMutable |
|
383 (JNIEnv* aEnv, jclass, jint aHImage2D) |
|
384 { |
|
385 M3G_DO_LOCK |
|
386 jboolean isMutable = (jboolean)m3gIsMutable((M3GImage)aHImage2D); |
|
387 M3G_DO_UNLOCK(aEnv) |
|
388 return isMutable; |
|
389 } |
|
390 |
|
391 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1getHeight |
|
392 (JNIEnv* aEnv, jclass, jint aHImage2D) |
|
393 { |
|
394 M3G_DO_LOCK |
|
395 jint height = (jint)m3gGetHeight((M3GImage)aHImage2D); |
|
396 M3G_DO_UNLOCK(aEnv) |
|
397 return height; |
|
398 } |
|
399 |
|
400 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1ctorSize |
|
401 (JNIEnv* aEnv, jclass, jint aM3g, jint aFormat, jint aWidth, jint aHeight) |
|
402 { |
|
403 M3G_DO_LOCK |
|
404 jint handle = (M3Guint) m3gCreateImage((M3GInterface)aM3g, |
|
405 (M3GImageFormat)aFormat, |
|
406 aWidth, aHeight, |
|
407 M3G_DYNAMIC|M3G_RENDERING_TARGET); |
|
408 M3G_DO_UNLOCK(aEnv) |
|
409 return handle; |
|
410 } |
|
411 |
|
412 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1getWidth |
|
413 (JNIEnv* aEnv, jclass, jint aHImage2D) |
|
414 { |
|
415 M3G_DO_LOCK |
|
416 jint width = (jint)m3gGetWidth((M3GImage)aHImage2D); |
|
417 M3G_DO_UNLOCK(aEnv) |
|
418 return width; |
|
419 } |
|
420 |
|
421 |
|
422 JNIEXPORT jint JNICALL Java_javax_microedition_m3g_Image2D__1ctorSizePixels |
|
423 (JNIEnv* aEnv, jclass, jint aM3g, jint aFormat, jint aWidth, jint aHeight, jbyteArray aImage) |
|
424 { |
|
425 M3GImageFormat format = (M3GImageFormat)aFormat; |
|
426 |
|
427 if (validateArray(aEnv, aImage, jsr184BytesPerPixel(format) * aWidth * aHeight)) |
|
428 { |
|
429 M3G_DO_LOCK |
|
430 |
|
431 M3GImage hImg = m3gCreateImage((M3GInterface)aM3g, format, aWidth, aHeight, 0); |
|
432 if (hImg != NULL) |
|
433 { |
|
434 M3GImageFormat format = (M3GImageFormat)aFormat; |
|
435 |
|
436 int bpp = jsr184BytesPerPixel(format); |
|
437 jbyte* imageScanline = (jbyte*)malloc(aWidth * bpp); |
|
438 for (int i=0; i < aHeight; i++) |
|
439 { |
|
440 aEnv->GetByteArrayRegion(aImage, aWidth * i * bpp, aWidth * bpp, imageScanline); |
|
441 m3gSetSubImage(hImg, 0, i, aWidth, 1, aWidth * bpp, imageScanline); |
|
442 } |
|
443 m3gCommitImage(hImg); |
|
444 |
|
445 free(imageScanline); |
|
446 } |
|
447 M3G_DO_UNLOCK(aEnv) |
|
448 return (unsigned) hImg; |
|
449 } |
|
450 return 0; |
|
451 } |