Lua: use rb->screens[] to do painting
[kugel-rb.git] / apps / plugins / lua / rocklib.c
blobb8d6eeb9649aefade71f898894faa7b483c64238
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Dan Everton (safetydan)
11 * Copyright (C) 2009 Maurus Cuelenaere
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #define lrocklib_c
24 #define LUA_LIB
26 #include "lua.h"
28 #include "lauxlib.h"
29 #include "rocklib.h"
32 * http://www.lua.org/manual/5.1/manual.html#lua_CFunction
34 * In order to communicate properly with Lua, a C function must use the following protocol,
35 * which defines the way parameters and results are passed: a C function receives its arguments
36 * from Lua in its stack in direct order (the first argument is pushed first). To return values to Lua,
37 * a C function just pushes them onto the stack, in direct order (the first result is pushed first),
38 * and returns the number of results. Any other value in the stack below the results will be properly
39 * discarded by Lua. Like a Lua function, a C function called by Lua can also return many results.
44 * -----------------------------
46 * Rockbox Lua image wrapper
48 * -----------------------------
51 #define ROCKLUA_IMAGE "rb.image"
52 struct rocklua_image
54 int width;
55 int height;
56 fb_data *data;
57 fb_data dummy[1][1];
60 static void rli_wrap(lua_State *L, fb_data *src, int width, int height)
62 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, sizeof(struct rocklua_image));
64 luaL_getmetatable(L, ROCKLUA_IMAGE);
65 lua_setmetatable(L, -2);
67 a->width = width;
68 a->height = height;
69 a->data = src;
72 static fb_data* rli_alloc(lua_State *L, int width, int height)
74 size_t nbytes = sizeof(struct rocklua_image) + ((width*height) - 1) * sizeof(fb_data);
75 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, nbytes);
77 luaL_getmetatable(L, ROCKLUA_IMAGE);
78 lua_setmetatable(L, -2);
80 a->width = width;
81 a->height = height;
82 a->data = &a->dummy[0][0];
84 return a->data;
87 static int rli_new(lua_State *L)
89 int width = luaL_checkint(L, 1);
90 int height = luaL_checkint(L, 2);
92 rli_alloc(L, width, height);
94 return 1;
97 static struct rocklua_image* rli_checktype(lua_State *L, int arg)
99 void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE);
100 luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected");
101 return (struct rocklua_image*) ud;
104 static int rli_width(lua_State *L)
106 struct rocklua_image *a = rli_checktype(L, 1);
107 lua_pushnumber(L, a->width);
108 return 1;
111 static int rli_height(lua_State *L)
113 struct rocklua_image *a = rli_checktype(L, 1);
114 lua_pushnumber(L, a->height);
115 return 1;
118 static fb_data* rli_element(lua_State *L)
120 struct rocklua_image *a = rli_checktype(L, 1);
121 int x = luaL_checkint(L, 2);
122 int y = luaL_checkint(L, 3);
124 luaL_argcheck(L, 1 <= x && x <= a->width, 2,
125 "index out of range");
126 luaL_argcheck(L, 1 <= y && y <= a->height, 3,
127 "index out of range");
129 /* return element address */
130 return &a->data[a->width * (y - 1) + (x - 1)];
133 static int rli_set(lua_State *L)
135 fb_data newvalue = (fb_data) luaL_checknumber(L, 4);
136 *rli_element(L) = newvalue;
137 return 0;
140 static int rli_get(lua_State *L)
142 lua_pushnumber(L, *rli_element(L));
143 return 1;
146 static int rli_tostring(lua_State *L)
148 struct rocklua_image *a = rli_checktype(L, 1);
149 lua_pushfstring(L, ROCKLUA_IMAGE ": %dx%d", a->width, a->height);
150 return 1;
153 static const struct luaL_reg rli_lib [] =
155 {"__tostring", rli_tostring},
156 {"set", rli_set},
157 {"get", rli_get},
158 {"width", rli_width},
159 {"height", rli_height},
160 {NULL, NULL}
163 static inline void rli_init(lua_State *L)
165 luaL_newmetatable(L, ROCKLUA_IMAGE);
167 lua_pushstring(L, "__index");
168 lua_pushvalue(L, -2); /* pushes the metatable */
169 lua_settable(L, -3); /* metatable.__index = metatable */
171 luaL_register(L, NULL, rli_lib);
175 * -----------------------------
177 * Rockbox wrappers start here!
179 * -----------------------------
182 #define RB_WRAP(M) static int rock_##M(lua_State *L)
184 /* Helper function for opt_viewport */
185 static void check_tablevalue(lua_State *L, const char* key, int tablepos, void* res, bool unsigned_val)
187 lua_getfield(L, tablepos, key); /* Find table[key] */
189 if(!lua_isnoneornil(L, -1))
191 if(unsigned_val)
192 *(unsigned*)res = luaL_checkint(L, -1);
193 else
194 *(int*)res = luaL_checkint(L, -1);
197 lua_pop(L, 1); /* Pop the value off the stack */
200 static struct viewport* opt_viewport(lua_State *L, int narg, struct viewport* alt)
202 if(lua_isnoneornil(L, narg))
203 return alt;
205 int tablepos = lua_gettop(L);
206 struct viewport *vp;
208 lua_getfield(L, tablepos, "vp"); /* get table['vp'] */
209 if(lua_isnoneornil(L, -1))
211 lua_pop(L, 1); /* Pop nil off stack */
213 vp = (struct viewport*) lua_newuserdata(L, sizeof(struct viewport)); /* Allocate memory and push it as udata on the stack */
214 memset(vp, 0, sizeof(struct viewport)); /* Init viewport values to 0 */
215 lua_setfield(L, tablepos, "vp"); /* table['vp'] = vp (pops value off the stack) */
217 else
219 vp = (struct viewport*) lua_touserdata(L, -1); /* Reuse viewport struct */
220 lua_pop(L, 1); /* We don't need the value on stack */
223 luaL_checktype(L, narg, LUA_TTABLE);
225 check_tablevalue(L, "x", tablepos, &vp->x, false);
226 check_tablevalue(L, "y", tablepos, &vp->y, false);
227 check_tablevalue(L, "width", tablepos, &vp->width, false);
228 check_tablevalue(L, "height", tablepos, &vp->height, false);
229 #ifdef HAVE_LCD_BITMAP
230 check_tablevalue(L, "font", tablepos, &vp->font, false);
231 check_tablevalue(L, "drawmode", tablepos, &vp->drawmode, false);
232 #endif
233 #if LCD_DEPTH > 1
234 check_tablevalue(L, "fg_pattern", tablepos, &vp->fg_pattern, true);
235 check_tablevalue(L, "bg_pattern", tablepos, &vp->bg_pattern, true);
236 #ifdef HAVE_LCD_COLOR
237 check_tablevalue(L, "lss_pattern", tablepos, &vp->lss_pattern, true);
238 check_tablevalue(L, "lse_pattern", tablepos, &vp->lse_pattern, true);
239 check_tablevalue(L, "lst_pattern", tablepos, &vp->lst_pattern, true);
240 #endif
241 #endif
243 return vp;
246 RB_WRAP(set_viewport)
248 struct viewport *vp = opt_viewport(L, 1, NULL);
249 int screen = luaL_optint(L, 2, SCREEN_MAIN);
250 rb->screens[screen]->set_viewport(vp);
251 return 0;
254 RB_WRAP(clear_viewport)
256 int screen = luaL_optint(L, 1, SCREEN_MAIN);
257 rb->screens[screen]->clear_viewport();
258 return 0;
261 #ifdef HAVE_LCD_BITMAP
262 RB_WRAP(lcd_framebuffer)
264 rli_wrap(L, rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT);
265 return 1;
268 RB_WRAP(lcd_mono_bitmap_part)
270 struct rocklua_image *src = rli_checktype(L, 1);
271 int src_x = luaL_checkint(L, 2);
272 int src_y = luaL_checkint(L, 3);
273 int stride = luaL_checkint(L, 4);
274 int x = luaL_checkint(L, 5);
275 int y = luaL_checkint(L, 6);
276 int width = luaL_checkint(L, 7);
277 int height = luaL_checkint(L, 8);
278 int screen = luaL_optint(L, 9, SCREEN_MAIN);
280 rb->screens[screen]->mono_bitmap_part((const unsigned char *)src->data, src_x, src_y, stride, x, y, width, height);
281 return 0;
284 RB_WRAP(lcd_mono_bitmap)
286 struct rocklua_image *src = rli_checktype(L, 1);
287 int x = luaL_checkint(L, 2);
288 int y = luaL_checkint(L, 3);
289 int width = luaL_checkint(L, 4);
290 int height = luaL_checkint(L, 5);
291 int screen = luaL_optint(L, 6, SCREEN_MAIN);
293 rb->screens[screen]->mono_bitmap((const unsigned char *)src->data, x, y, width, height);
294 return 0;
297 #if LCD_DEPTH > 1
298 RB_WRAP(lcd_bitmap_part)
300 struct rocklua_image *src = rli_checktype(L, 1);
301 int src_x = luaL_checkint(L, 2);
302 int src_y = luaL_checkint(L, 3);
303 int stride = luaL_checkint(L, 4);
304 int x = luaL_checkint(L, 5);
305 int y = luaL_checkint(L, 6);
306 int width = luaL_checkint(L, 7);
307 int height = luaL_checkint(L, 8);
308 int screen = luaL_optint(L, 9, SCREEN_MAIN);
310 rb->screens[screen]->bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
311 return 0;
314 RB_WRAP(lcd_bitmap)
316 struct rocklua_image *src = rli_checktype(L, 1);
317 int x = luaL_checkint(L, 2);
318 int y = luaL_checkint(L, 3);
319 int width = luaL_checkint(L, 4);
320 int height = luaL_checkint(L, 5);
321 int screen = luaL_optint(L, 6, SCREEN_MAIN);
323 rb->screens[screen]->bitmap(src->data, x, y, width, height);
324 return 0;
327 RB_WRAP(lcd_get_backdrop)
329 fb_data* backdrop = rb->lcd_get_backdrop();
330 if(backdrop == NULL)
331 return 0;
332 else
334 rli_wrap(L, backdrop, LCD_WIDTH, LCD_HEIGHT);
335 return 1;
338 #endif /* LCD_DEPTH > 1 */
340 #if LCD_DEPTH == 16
341 RB_WRAP(lcd_bitmap_transparent_part)
343 struct rocklua_image *src = rli_checktype(L, 1);
344 int src_x = luaL_checkint(L, 2);
345 int src_y = luaL_checkint(L, 3);
346 int stride = luaL_checkint(L, 4);
347 int x = luaL_checkint(L, 5);
348 int y = luaL_checkint(L, 6);
349 int width = luaL_checkint(L, 7);
350 int height = luaL_checkint(L, 8);
351 int screen = luaL_optint(L, 9, SCREEN_MAIN);
353 rb->screens[screen]->transparent_bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
354 return 0;
357 RB_WRAP(lcd_bitmap_transparent)
359 struct rocklua_image *src = rli_checktype(L, 1);
360 int x = luaL_checkint(L, 2);
361 int y = luaL_checkint(L, 3);
362 int width = luaL_checkint(L, 4);
363 int height = luaL_checkint(L, 5);
364 int screen = luaL_optint(L, 6, SCREEN_MAIN);
366 rb->screens[screen]->transparent_bitmap(src->data, x, y, width, height);
367 return 0;
369 #endif /* LCD_DEPTH == 16 */
371 #endif /* defined(LCD_BITMAP) */
373 RB_WRAP(current_tick)
375 lua_pushinteger(L, *rb->current_tick);
376 return 1;
379 #ifdef HAVE_TOUCHSCREEN
380 RB_WRAP(action_get_touchscreen_press)
382 short x, y;
383 int result = rb->action_get_touchscreen_press(&x, &y);
385 lua_pushinteger(L, result);
386 lua_pushinteger(L, x);
387 lua_pushinteger(L, y);
388 return 3;
390 #endif
392 RB_WRAP(kbd_input)
394 luaL_Buffer b;
395 luaL_buffinit(L, &b);
397 char *buffer = luaL_prepbuffer(&b);
398 buffer[0] = '\0';
399 rb->kbd_input(buffer, LUAL_BUFFERSIZE);
400 luaL_addsize(&b, strlen(buffer));
402 luaL_pushresult(&b);
403 return 1;
406 #ifdef HAVE_TOUCHSCREEN
407 RB_WRAP(touchscreen_set_mode)
409 enum touchscreen_mode mode = luaL_checkint(L, 1);
410 rb->touchscreen_set_mode(mode);
411 return 0;
413 #endif
415 RB_WRAP(font_getstringsize)
417 const unsigned char* str = luaL_checkstring(L, 1);
418 int fontnumber = luaL_checkint(L, 2);
419 int w, h;
421 int result = rb->font_getstringsize(str, &w, &h, fontnumber);
422 lua_pushinteger(L, result);
423 lua_pushinteger(L, w);
424 lua_pushinteger(L, h);
426 return 3;
429 #ifdef HAVE_LCD_COLOR
430 RB_WRAP(lcd_rgbpack)
432 int r = luaL_checkint(L, 1);
433 int g = luaL_checkint(L, 2);
434 int b = luaL_checkint(L, 3);
435 int result = LCD_RGBPACK(r, g, b);
436 lua_pushinteger(L, result);
437 return 1;
440 RB_WRAP(lcd_rgbunpack)
442 int rgb = luaL_checkint(L, 1);
443 lua_pushinteger(L, RGB_UNPACK_RED(rgb));
444 lua_pushinteger(L, RGB_UNPACK_GREEN(rgb));
445 lua_pushinteger(L, RGB_UNPACK_BLUE(rgb));
446 return 3;
448 #endif
450 RB_WRAP(read_bmp_file)
452 struct bitmap bm;
453 const char* filename = luaL_checkstring(L, 1);
454 bool dither = luaL_optboolean(L, 2, true);
455 bool transparent = luaL_optboolean(L, 3, false);
456 int format = FORMAT_NATIVE;
458 if(dither)
459 format |= FORMAT_DITHER;
461 if(transparent)
462 format |= FORMAT_TRANSPARENT;
464 int result = rb->read_bmp_file(filename, &bm, 0, format | FORMAT_RETURN_SIZE, NULL);
466 if(result > 0)
468 bm.data = (unsigned char*) rli_alloc(L, bm.width, bm.height);
469 rb->read_bmp_file(filename, &bm, result, format, NULL);
471 return 1;
474 return 0;
477 RB_WRAP(current_path)
479 const char *current_path = get_current_path(L, 1);
480 if(current_path != NULL)
482 lua_pushstring(L, current_path);
483 return 1;
485 else
486 return 0;
489 static void fill_text_message(lua_State *L, struct text_message * message,
490 int pos)
492 int i;
493 luaL_checktype(L, pos, LUA_TTABLE);
494 int n = luaL_getn(L, pos);
495 const char **lines = (const char**) dlmalloc(n * sizeof(const char*));
496 for(i=1; i<=n; i++)
498 lua_rawgeti(L, pos, i);
499 lines[i-1] = luaL_checkstring(L, -1);
500 lua_pop(L, 1);
502 message->message_lines = lines;
503 message->nb_lines = n;
506 RB_WRAP(gui_syncyesno_run)
508 struct text_message main_message, yes_message, no_message;
509 struct text_message *yes = NULL, *no = NULL;
511 fill_text_message(L, &main_message, 1);
512 if(!lua_isnoneornil(L, 2))
513 fill_text_message(L, (yes = &yes_message), 2);
514 if(!lua_isnoneornil(L, 3))
515 fill_text_message(L, (no = &no_message), 3);
517 enum yesno_res result = rb->gui_syncyesno_run(&main_message, yes, no);
519 dlfree(main_message.message_lines);
520 if(yes)
521 dlfree(yes_message.message_lines);
522 if(no)
523 dlfree(no_message.message_lines);
525 lua_pushinteger(L, result);
526 return 1;
529 #define R(NAME) {#NAME, rock_##NAME}
530 static const luaL_Reg rocklib[] =
532 /* Graphics */
533 #ifdef HAVE_LCD_BITMAP
534 R(lcd_framebuffer),
535 R(lcd_mono_bitmap_part),
536 R(lcd_mono_bitmap),
537 #if LCD_DEPTH > 1
538 R(lcd_get_backdrop),
539 R(lcd_bitmap_part),
540 R(lcd_bitmap),
541 #endif
542 #if LCD_DEPTH == 16
543 R(lcd_bitmap_transparent_part),
544 R(lcd_bitmap_transparent),
545 #endif
546 #endif
547 #ifdef HAVE_LCD_COLOR
548 R(lcd_rgbpack),
549 R(lcd_rgbunpack),
550 #endif
552 /* Kernel */
553 R(current_tick),
555 /* Buttons */
556 #ifdef HAVE_TOUCHSCREEN
557 R(action_get_touchscreen_press),
558 R(touchscreen_set_mode),
559 #endif
560 R(kbd_input),
562 R(font_getstringsize),
563 R(read_bmp_file),
564 R(set_viewport),
565 R(clear_viewport),
566 R(current_path),
567 R(gui_syncyesno_run),
569 {"new_image", rli_new},
571 {NULL, NULL}
573 #undef R
574 extern const luaL_Reg rocklib_aux[];
577 #define RB_CONSTANT(x) lua_pushinteger(L, x); lua_setfield(L, -2, #x);
579 ** Open Rockbox library
581 LUALIB_API int luaopen_rock(lua_State *L)
583 luaL_register(L, LUA_ROCKLIBNAME, rocklib);
584 luaL_register(L, LUA_ROCKLIBNAME, rocklib_aux);
586 RB_CONSTANT(HZ);
588 RB_CONSTANT(LCD_WIDTH);
589 RB_CONSTANT(LCD_HEIGHT);
591 RB_CONSTANT(FONT_SYSFIXED);
592 RB_CONSTANT(FONT_UI);
594 #ifdef HAVE_TOUCHSCREEN
595 RB_CONSTANT(TOUCHSCREEN_POINT);
596 RB_CONSTANT(TOUCHSCREEN_BUTTON);
597 #endif
599 rli_init(L);
601 return 1;