source: trunk/src/image.cpp @ 863

Last change on this file since 863 was 863, checked in by sam, 10 years ago

core: rename vec2i to ivec2 etc. to better match GLSL.

File size: 9.7 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 JNIEnv *g_env;
39extern jobject g_ctx;
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    jclass cls = g_env->GetObjectClass(g_ctx);
130    jmethodID mid;
131
132    mid = g_env->GetMethodID(cls, "openImage",
133                             "(Ljava/lang/String;)Landroid/graphics/Bitmap;");
134    jstring name = g_env->NewStringUTF(path);
135    data->bmp = g_env->CallObjectMethod(g_ctx, mid, name);
136    g_env->DeleteLocalRef(name);
137    if (!data->bmp)
138    {
139#if !LOL_RELEASE
140        Log::Error("could not load %s\n", path);
141#endif
142        exit(1);
143    }
144    g_env->NewGlobalRef(data->bmp);
145
146    /* Get image dimensions */
147    mid = g_env->GetMethodID(cls, "getWidth", "(Landroid/graphics/Bitmap;)I");
148    data->size.x = g_env->CallIntMethod(g_ctx, mid, data->bmp);
149    mid = g_env->GetMethodID(cls, "getHeight", "(Landroid/graphics/Bitmap;)I");
150    data->size.y = g_env->CallIntMethod(g_ctx, mid, data->bmp);
151
152    /* Get pixels */
153    data->array = g_env->NewIntArray(data->size.x * data->size.y);
154    g_env->NewGlobalRef(data->array);
155    mid = g_env->GetMethodID(cls, "getPixels", "(Landroid/graphics/Bitmap;[I)V");
156    g_env->CallVoidMethod(g_ctx, mid, data->bmp, data->array);
157
158    data->pixels = g_env->GetIntArrayElements(data->array, 0);
159    for (int n = 0; n < data->size.x * data->size.y; n++)
160    {
161        uint32_t u = data->pixels[n];
162        u = (u & 0xff00ff00) | ((u & 0xff0000) >> 16) | ((u & 0xff) << 16);
163        data->pixels[n] = u;
164    }
165    data->format = FORMAT_RGBA;
166#elif defined __CELLOS_LV2__
167    int32_t err;
168
169    /* Initialise decoding library */
170    CellPngDecMainHandle hmain;
171
172    err = cellSysmoduleLoadModule(CELL_SYSMODULE_FS);
173    if (err != CELL_OK)
174    {
175#if !LOL_RELEASE
176        Log::Error("could not open Fs sysmodule\n");
177#endif
178        exit(1);
179    }
180
181    err = cellSysmoduleLoadModule(CELL_SYSMODULE_PNGDEC);
182    if (err != CELL_OK)
183    {
184#if !LOL_RELEASE
185        Log::Error("could not open PngDec sysmodule\n");
186#endif
187        exit(1);
188    }
189
190    CellPngDecThreadInParam in_param;
191    in_param.spuThreadEnable = CELL_PNGDEC_SPU_THREAD_ENABLE;
192    in_param.ppuThreadPriority = 1000;
193    in_param.spuThreadPriority = 200;
194    in_param.cbCtrlMallocFunc = ImageData::Malloc;
195    in_param.cbCtrlMallocArg = NULL;
196    in_param.cbCtrlFreeFunc = ImageData::Free;
197    in_param.cbCtrlFreeArg = NULL;
198    CellPngDecThreadOutParam out_param;
199    err = cellPngDecCreate(&hmain, &in_param, &out_param);
200    if (err != CELL_OK)
201    {
202#if !LOL_RELEASE
203        Log::Error("could not create PngDec library\n");
204#endif
205        exit(1);
206    }
207
208    /* Create decoder */
209    CellPngDecSubHandle hsub;
210
211    char file[1024];
212    sprintf(file, "/app_home/c:/Users/s.hocevar/lolengine/%s", path);
213
214    CellPngDecSrc dec_src;
215    dec_src.srcSelect = CELL_PNGDEC_FILE;
216    dec_src.fileName = file;
217    dec_src.fileOffset = 0;
218    dec_src.fileSize = 0;
219    dec_src.streamPtr = NULL;
220    dec_src.streamSize = 0;
221    dec_src.spuThreadEnable  = CELL_PNGDEC_SPU_THREAD_ENABLE;
222    CellPngDecOpnInfo open_info;
223    err = cellPngDecOpen(hmain, &hsub, &dec_src, &open_info);
224    if (err != CELL_OK)
225    {
226#if !LOL_RELEASE
227        Log::Error("could not open %s for decoding\n", file);
228#endif
229        exit(1);
230    }
231
232    CellPngDecInfo info;
233    err = cellPngDecReadHeader(hmain, hsub, &info);
234    if (err != CELL_OK)
235    {
236#if !LOL_RELEASE
237        Log::Error("could not read image header\n");
238#endif
239        exit(1);
240    }
241
242    CellPngDecInParam in_dec_param;
243    in_dec_param.commandPtr = NULL;
244    in_dec_param.outputMode = CELL_PNGDEC_TOP_TO_BOTTOM;
245    in_dec_param.outputColorSpace = CELL_PNGDEC_RGBA;
246    in_dec_param.outputBitDepth = 8;
247    in_dec_param.outputPackFlag = CELL_PNGDEC_1BYTE_PER_1PIXEL;
248    in_dec_param.outputAlphaSelect = CELL_PNGDEC_STREAM_ALPHA;
249    in_dec_param.outputColorAlpha = 0xff;
250    CellPngDecOutParam out_dec_param;
251    err = cellPngDecSetParameter(hmain, hsub, &in_dec_param, &out_dec_param);
252    if (err != CELL_OK)
253    {
254#if !LOL_RELEASE
255        Log::Error("could not configure PngDec decoder\n");
256#endif
257        exit(1);
258    }
259
260    /* Decode image */
261    data->size = ivec2(info.imageWidth, info.imageHeight);
262    data->format = FORMAT_RGBA;
263    data->pixels = (uint8_t *)malloc(info.imageWidth * 4 * info.imageHeight);
264    CellPngDecDataCtrlParam data_ctrl_param;
265    data_ctrl_param.outputBytesPerLine = info.imageWidth * 4;
266    CellPngDecDataOutInfo data_out_info;
267    err = cellPngDecDecodeData(hmain, hsub, data->pixels,
268                               &data_ctrl_param, &data_out_info);
269    if (err != CELL_OK)
270    {
271#if !LOL_RELEASE
272        Log::Error("could not run PngDec decoder\n");
273#endif
274        exit(1);
275    }
276
277    /* Close decoder */
278    err = cellPngDecClose(hmain, hsub);
279    if (err != CELL_OK)
280    {
281#if !LOL_RELEASE
282        Log::Error("could not close PngDec decoder\n");
283#endif
284        exit(1);
285    }
286
287    /* Deinitialise library */
288    err = cellPngDecDestroy(hmain);
289    if (err != CELL_OK)
290    {
291#if !LOL_RELEASE
292        Log::Error("could not destroy PngDec decoder\n");
293#endif
294        exit(1);
295    }
296    err = cellSysmoduleUnloadModule(CELL_SYSMODULE_PNGDEC);
297    err = cellSysmoduleUnloadModule(CELL_SYSMODULE_FS);
298#else
299    data->size = 256;
300    data->format = FORMAT_RGBA;
301    data->pixels = (uint8_t *)malloc(256 * 256 * 4 * sizeof(*data->pixels));
302    uint8_t *parser = data->pixels;
303    for (int j = 0; j < 256; j++)
304        for (int i = 0; i < 256; i++)
305        {
306            *parser++ = ((i ^ j) & 1) * 0xff;
307            *parser++ = (uint8_t)i;
308            *parser++ = (uint8_t)j;
309            *parser++ = (((i >> 4) ^ (j >> 4)) & 1) * 0xff;
310        }
311#endif
312}
313
314ivec2 Image::GetSize() const
315{
316    return data->size;
317}
318
319Image::format_t Image::GetFormat() const
320{
321    return data->format;
322}
323
324void * Image::GetData() const
325{
326#if defined __APPLE__ && defined __MACH__
327    return data->pixels;
328#elif defined USE_SDL
329    return data->img->pixels;
330#elif defined ANDROID_NDK
331    return data->pixels;
332#elif defined __CELLOS_LV2__
333    return data->pixels;
334#else
335    return data->pixels;
336#endif
337}
338
339Image::~Image()
340{
341#if defined __APPLE__ && defined __MACH__
342    free(data->pixels);
343#elif defined USE_SDL
344    SDL_FreeSurface(data->img);
345#elif defined ANDROID_NDK
346    jclass cls = g_env->GetObjectClass(g_ctx);
347    jmethodID mid;
348
349    g_env->ReleaseIntArrayElements(data->array, data->pixels, 0);
350    g_env->DeleteGlobalRef(data->array);
351
352    /* Free image */
353    mid = g_env->GetMethodID(cls, "closeImage", "(Landroid/graphics/Bitmap;)V");
354    g_env->CallVoidMethod(g_ctx, mid, data->bmp);
355    g_env->DeleteGlobalRef(data->bmp);
356#elif defined __CELLOS_LV2__
357    free(data->pixels);
358#else
359    free(data->pixels);
360#endif
361    delete data;
362}
363
364} /* namespace lol */
365
Note: See TracBrowser for help on using the repository browser.