source: trunk/src/image/image.cpp @ 864

Last change on this file since 864 was 864, checked in by sam, 12 years ago

android: keep a pointer on the global Java VM instead of the current
environment, so back-to-jvm techniques can work from any thread.

  • Property svn:keywords set to Id
File size: 10.1 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cmath>
16
17#if defined __APPLE__ && defined __MACH__
18#   import <UIKit/UIKit.h>
19#elif defined USE_SDL
20#   include <SDL.h>
21#   include <SDL_image.h>
22#elif defined ANDROID_NDK
23#   include <jni.h>
24#   include <android/log.h>
25#elif defined __CELLOS_LV2__
26#   include <cell/sysmodule.h>
27#   include <cell/codec/pngdec.h>
28#endif
29
30#include "core.h"
31
32using namespace std;
33
34namespace lol
35{
36
37#if defined ANDROID_NDK
38extern JavaVM *g_vm;
39extern jobject g_activity;
40#endif
41
42/*
43 * Image implementation class
44 */
45
46class ImageData
47{
48    friend class Image;
49
50private:
51    ivec2 size;
52    Image::format_t format;
53
54#if defined __APPLE__ && defined __MACH__
55    uint8_t *pixels;
56#elif defined USE_SDL
57    SDL_Surface *img;
58#elif defined ANDROID_NDK
59    jobject bmp;
60    jintArray array;
61    jint *pixels;
62#elif defined __CELLOS_LV2__
63    static void* Malloc(uint32_t size, void* data) { return malloc(size); };
64    static int32_t Free(void* ptr, void* data) { free(ptr); return 0; };
65    uint8_t *pixels;
66#else
67    uint8_t *pixels;
68#endif
69};
70
71/*
72 * Public Image class
73 */
74
75Image::Image(char const *path)
76  : data(new ImageData())
77{
78#if defined __APPLE__ && defined __MACH__
79    NSString *fullpath = [NSString stringWithUTF8String:path];
80    NSArray *chunks = [fullpath componentsSeparatedByString: @"/"];
81    NSString *filename = [chunks objectAtIndex: [chunks count] - 1];
82    chunks = [filename componentsSeparatedByString: @"."];
83    NSString *prefix = [chunks objectAtIndex: 0];
84    NSString *mypath = [[NSBundle mainBundle] pathForResource:prefix ofType:@"png"];
85    NSData *pngdata = [[NSData alloc] initWithContentsOfFile:mypath];
86    UIImage *image = [[UIImage alloc] initWithData:pngdata];
87    if (!image)
88    {
89#if !LOL_RELEASE
90        Log::Error("could not load %s\n", path);
91#endif
92        exit(1);
93    }
94
95    int w = CGImageGetWidth(image.CGImage);
96    int h = CGImageGetHeight(image.CGImage);
97    data->size = ivec2(w, h);
98    data->format = FORMAT_RGBA;
99
100    CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
101    data->pixels = (uint8_t *)malloc(w * h * 4);
102    CGContextRef ctx =
103            CGBitmapContextCreate(data->pixels, w, h, 8, 4 * w, cspace,
104                    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
105    CGColorSpaceRelease(cspace);
106    CGContextClearRect(ctx, CGRectMake(0, 0, w, h));
107    CGContextTranslateCTM(ctx, 0, h - h);
108    CGContextDrawImage(ctx, CGRectMake(0, 0, w, h), image.CGImage);
109    CGContextRelease(ctx);
110    [image release];
111    [pngdata release];
112#elif defined USE_SDL
113    for (char const *name = path; *name; name++)
114        if ((data->img = IMG_Load(name)))
115            break;
116
117    if (!data->img)
118    {
119#if !LOL_RELEASE
120        Log::Error("could not load %s\n", path);
121#endif
122        SDL_Quit();
123        exit(1);
124    }
125
126    data->size = ivec2(data->img->w, data->img->h);
127    data->format = data->img->format->Amask ? FORMAT_RGBA : FORMAT_RGB;
128#elif defined ANDROID_NDK
129    JNIEnv *env;
130    jint res = g_vm->GetEnv((void **)&env, JNI_VERSION_1_2);
131    if (res < 0)
132    {
133#if !LOL_RELEASE
134        Log::Error("could not get JVM environment\n");
135#endif
136        exit(1);
137    }
138    jclass cls = env->GetObjectClass(g_activity);
139    jmethodID mid;
140
141    mid = env->GetMethodID(cls, "openImage",
142                           "(Ljava/lang/String;)Landroid/graphics/Bitmap;");
143    jstring name = env->NewStringUTF(path);
144    data->bmp = env->CallObjectMethod(g_activity, mid, name);
145    env->DeleteLocalRef(name);
146    if (!data->bmp)
147    {
148#if !LOL_RELEASE
149        Log::Error("could not load %s\n", path);
150#endif
151        exit(1);
152    }
153    env->NewGlobalRef(data->bmp);
154
155    /* Get image dimensions */
156    mid = env->GetMethodID(cls, "getWidth", "(Landroid/graphics/Bitmap;)I");
157    data->size.x = env->CallIntMethod(g_activity, mid, data->bmp);
158    mid = env->GetMethodID(cls, "getHeight", "(Landroid/graphics/Bitmap;)I");
159    data->size.y = env->CallIntMethod(g_activity, mid, data->bmp);
160
161    /* Get pixels */
162    data->array = env->NewIntArray(data->size.x * data->size.y);
163    env->NewGlobalRef(data->array);
164    mid = env->GetMethodID(cls, "getPixels", "(Landroid/graphics/Bitmap;[I)V");
165    env->CallVoidMethod(g_activity, mid, data->bmp, data->array);
166
167    data->pixels = env->GetIntArrayElements(data->array, 0);
168    for (int n = 0; n < data->size.x * data->size.y; n++)
169    {
170        uint32_t u = data->pixels[n];
171        u = (u & 0xff00ff00) | ((u & 0xff0000) >> 16) | ((u & 0xff) << 16);
172        data->pixels[n] = u;
173    }
174    data->format = FORMAT_RGBA;
175#elif defined __CELLOS_LV2__
176    int32_t err;
177
178    /* Initialise decoding library */
179    CellPngDecMainHandle hmain;
180
181    err = cellSysmoduleLoadModule(CELL_SYSMODULE_FS);
182    if (err != CELL_OK)
183    {
184#if !LOL_RELEASE
185        Log::Error("could not open Fs sysmodule\n");
186#endif
187        exit(1);
188    }
189
190    err = cellSysmoduleLoadModule(CELL_SYSMODULE_PNGDEC);
191    if (err != CELL_OK)
192    {
193#if !LOL_RELEASE
194        Log::Error("could not open PngDec sysmodule\n");
195#endif
196        exit(1);
197    }
198
199    CellPngDecThreadInParam in_param;
200    in_param.spuThreadEnable = CELL_PNGDEC_SPU_THREAD_ENABLE;
201    in_param.ppuThreadPriority = 1000;
202    in_param.spuThreadPriority = 200;
203    in_param.cbCtrlMallocFunc = ImageData::Malloc;
204    in_param.cbCtrlMallocArg = NULL;
205    in_param.cbCtrlFreeFunc = ImageData::Free;
206    in_param.cbCtrlFreeArg = NULL;
207    CellPngDecThreadOutParam out_param;
208    err = cellPngDecCreate(&hmain, &in_param, &out_param);
209    if (err != CELL_OK)
210    {
211#if !LOL_RELEASE
212        Log::Error("could not create PngDec library\n");
213#endif
214        exit(1);
215    }
216
217    /* Create decoder */
218    CellPngDecSubHandle hsub;
219
220    char file[1024];
221    sprintf(file, "/app_home/c:/Users/s.hocevar/lolengine/%s", path);
222
223    CellPngDecSrc dec_src;
224    dec_src.srcSelect = CELL_PNGDEC_FILE;
225    dec_src.fileName = file;
226    dec_src.fileOffset = 0;
227    dec_src.fileSize = 0;
228    dec_src.streamPtr = NULL;
229    dec_src.streamSize = 0;
230    dec_src.spuThreadEnable  = CELL_PNGDEC_SPU_THREAD_ENABLE;
231    CellPngDecOpnInfo open_info;
232    err = cellPngDecOpen(hmain, &hsub, &dec_src, &open_info);
233    if (err != CELL_OK)
234    {
235#if !LOL_RELEASE
236        Log::Error("could not open %s for decoding\n", file);
237#endif
238        exit(1);
239    }
240
241    CellPngDecInfo info;
242    err = cellPngDecReadHeader(hmain, hsub, &info);
243    if (err != CELL_OK)
244    {
245#if !LOL_RELEASE
246        Log::Error("could not read image header\n");
247#endif
248        exit(1);
249    }
250
251    CellPngDecInParam in_dec_param;
252    in_dec_param.commandPtr = NULL;
253    in_dec_param.outputMode = CELL_PNGDEC_TOP_TO_BOTTOM;
254    in_dec_param.outputColorSpace = CELL_PNGDEC_RGBA;
255    in_dec_param.outputBitDepth = 8;
256    in_dec_param.outputPackFlag = CELL_PNGDEC_1BYTE_PER_1PIXEL;
257    in_dec_param.outputAlphaSelect = CELL_PNGDEC_STREAM_ALPHA;
258    in_dec_param.outputColorAlpha = 0xff;
259    CellPngDecOutParam out_dec_param;
260    err = cellPngDecSetParameter(hmain, hsub, &in_dec_param, &out_dec_param);
261    if (err != CELL_OK)
262    {
263#if !LOL_RELEASE
264        Log::Error("could not configure PngDec decoder\n");
265#endif
266        exit(1);
267    }
268
269    /* Decode image */
270    data->size = ivec2(info.imageWidth, info.imageHeight);
271    data->format = FORMAT_RGBA;
272    data->pixels = (uint8_t *)malloc(info.imageWidth * 4 * info.imageHeight);
273    CellPngDecDataCtrlParam data_ctrl_param;
274    data_ctrl_param.outputBytesPerLine = info.imageWidth * 4;
275    CellPngDecDataOutInfo data_out_info;
276    err = cellPngDecDecodeData(hmain, hsub, data->pixels,
277                               &data_ctrl_param, &data_out_info);
278    if (err != CELL_OK)
279    {
280#if !LOL_RELEASE
281        Log::Error("could not run PngDec decoder\n");
282#endif
283        exit(1);
284    }
285
286    /* Close decoder */
287    err = cellPngDecClose(hmain, hsub);
288    if (err != CELL_OK)
289    {
290#if !LOL_RELEASE
291        Log::Error("could not close PngDec decoder\n");
292#endif
293        exit(1);
294    }
295
296    /* Deinitialise library */
297    err = cellPngDecDestroy(hmain);
298    if (err != CELL_OK)
299    {
300#if !LOL_RELEASE
301        Log::Error("could not destroy PngDec decoder\n");
302#endif
303        exit(1);
304    }
305    err = cellSysmoduleUnloadModule(CELL_SYSMODULE_PNGDEC);
306    err = cellSysmoduleUnloadModule(CELL_SYSMODULE_FS);
307#else
308    data->size = 256;
309    data->format = FORMAT_RGBA;
310    data->pixels = (uint8_t *)malloc(256 * 256 * 4 * sizeof(*data->pixels));
311    uint8_t *parser = data->pixels;
312    for (int j = 0; j < 256; j++)
313        for (int i = 0; i < 256; i++)
314        {
315            *parser++ = ((i ^ j) & 1) * 0xff;
316            *parser++ = (uint8_t)i;
317            *parser++ = (uint8_t)j;
318            *parser++ = (((i >> 4) ^ (j >> 4)) & 1) * 0xff;
319        }
320#endif
321}
322
323ivec2 Image::GetSize() const
324{
325    return data->size;
326}
327
328Image::format_t Image::GetFormat() const
329{
330    return data->format;
331}
332
333void * Image::GetData() const
334{
335#if defined __APPLE__ && defined __MACH__
336    return data->pixels;
337#elif defined USE_SDL
338    return data->img->pixels;
339#elif defined ANDROID_NDK
340    return data->pixels;
341#elif defined __CELLOS_LV2__
342    return data->pixels;
343#else
344    return data->pixels;
345#endif
346}
347
348Image::~Image()
349{
350#if defined __APPLE__ && defined __MACH__
351    free(data->pixels);
352#elif defined USE_SDL
353    SDL_FreeSurface(data->img);
354#elif defined ANDROID_NDK
355    JNIEnv *env;
356    jint res = g_vm->GetEnv((void **)&env, JNI_VERSION_1_2);
357    if (res < 0)
358    {
359#if !LOL_RELEASE
360        Log::Error("could not get JVM environment\n");
361#endif
362        exit(1);
363    }
364    jclass cls = env->GetObjectClass(g_activity);
365    jmethodID mid;
366
367    env->ReleaseIntArrayElements(data->array, data->pixels, 0);
368    env->DeleteGlobalRef(data->array);
369
370    /* Free image */
371    mid = env->GetMethodID(cls, "closeImage", "(Landroid/graphics/Bitmap;)V");
372    env->CallVoidMethod(g_activity, mid, data->bmp);
373    env->DeleteGlobalRef(data->bmp);
374#elif defined __CELLOS_LV2__
375    free(data->pixels);
376#else
377    free(data->pixels);
378#endif
379    delete data;
380}
381
382} /* namespace lol */
383
Note: See TracBrowser for help on using the repository browser.