Lua: add script which wraps not-yet ported C functions to Lua
[kugel-rb.git] / apps / plugins / lua / rocklib.c
blob69e26fdee69696d9f18313934be9bb5d59132506
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);
279 rb->lcd_mono_bitmap_part((const unsigned char *)src->data, src_x, src_y, stride, x, y, width, height);
280 return 0;
283 RB_WRAP(lcd_mono_bitmap)
285 struct rocklua_image *src = rli_checktype(L, 1);
286 int x = luaL_checkint(L, 2);
287 int y = luaL_checkint(L, 3);
288 int width = luaL_checkint(L, 4);
289 int height = luaL_checkint(L, 5);
291 rb->lcd_mono_bitmap((const unsigned char *)src->data, x, y, width, height);
292 return 0;
295 #if LCD_DEPTH > 1
296 RB_WRAP(lcd_bitmap_part)
298 struct rocklua_image *src = rli_checktype(L, 1);
299 int src_x = luaL_checkint(L, 2);
300 int src_y = luaL_checkint(L, 3);
301 int stride = luaL_checkint(L, 4);
302 int x = luaL_checkint(L, 5);
303 int y = luaL_checkint(L, 6);
304 int width = luaL_checkint(L, 7);
305 int height = luaL_checkint(L, 8);
307 rb->lcd_bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
308 return 0;
311 RB_WRAP(lcd_bitmap)
313 struct rocklua_image *src = rli_checktype(L, 1);
314 int x = luaL_checkint(L, 2);
315 int y = luaL_checkint(L, 3);
316 int width = luaL_checkint(L, 4);
317 int height = luaL_checkint(L, 5);
319 rb->lcd_bitmap(src->data, x, y, width, height);
320 return 0;
323 RB_WRAP(lcd_get_backdrop)
325 fb_data* backdrop = rb->lcd_get_backdrop();
326 if(backdrop == NULL)
327 return 0;
328 else
330 rli_wrap(L, backdrop, LCD_WIDTH, LCD_HEIGHT);
331 return 1;
334 #endif /* LCD_DEPTH > 1 */
336 #if LCD_DEPTH == 16
337 RB_WRAP(lcd_bitmap_transparent_part)
339 struct rocklua_image *src = rli_checktype(L, 1);
340 int src_x = luaL_checkint(L, 2);
341 int src_y = luaL_checkint(L, 3);
342 int stride = luaL_checkint(L, 4);
343 int x = luaL_checkint(L, 5);
344 int y = luaL_checkint(L, 6);
345 int width = luaL_checkint(L, 7);
346 int height = luaL_checkint(L, 8);
348 rb->lcd_bitmap_transparent_part(src->data, src_x, src_y, stride, x, y, width, height);
349 return 0;
352 RB_WRAP(lcd_bitmap_transparent)
354 struct rocklua_image *src = rli_checktype(L, 1);
355 int x = luaL_checkint(L, 2);
356 int y = luaL_checkint(L, 3);
357 int width = luaL_checkint(L, 4);
358 int height = luaL_checkint(L, 5);
360 rb->lcd_bitmap_transparent(src->data, x, y, width, height);
361 return 0;
363 #endif /* LCD_DEPTH == 16 */
365 #endif /* defined(LCD_BITMAP) */
367 RB_WRAP(current_tick)
369 lua_pushinteger(L, *rb->current_tick);
370 return 1;
373 #ifdef HAVE_TOUCHSCREEN
374 RB_WRAP(action_get_touchscreen_press)
376 short x, y;
377 int result = rb->action_get_touchscreen_press(&x, &y);
379 lua_pushinteger(L, result);
380 lua_pushinteger(L, x);
381 lua_pushinteger(L, y);
382 return 3;
384 #endif
386 RB_WRAP(kbd_input)
388 luaL_Buffer b;
389 luaL_buffinit(L, &b);
391 char *buffer = luaL_prepbuffer(&b);
392 buffer[0] = '\0';
393 rb->kbd_input(buffer, LUAL_BUFFERSIZE);
394 luaL_addsize(&b, strlen(buffer));
396 luaL_pushresult(&b);
397 return 1;
400 #ifdef HAVE_TOUCHSCREEN
401 RB_WRAP(touchscreen_set_mode)
403 enum touchscreen_mode mode = luaL_checkint(L, 1);
404 rb->touchscreen_set_mode(mode);
405 return 0;
407 #endif
409 RB_WRAP(font_getstringsize)
411 const unsigned char* str = luaL_checkstring(L, 1);
412 int fontnumber = luaL_checkint(L, 2);
413 int w, h;
415 int result = rb->font_getstringsize(str, &w, &h, fontnumber);
416 lua_pushinteger(L, result);
417 lua_pushinteger(L, w);
418 lua_pushinteger(L, h);
420 return 3;
423 #ifdef HAVE_LCD_COLOR
424 RB_WRAP(lcd_rgbpack)
426 int r = luaL_checkint(L, 1);
427 int g = luaL_checkint(L, 2);
428 int b = luaL_checkint(L, 3);
429 int result = LCD_RGBPACK(r, g, b);
430 lua_pushinteger(L, result);
431 return 1;
434 RB_WRAP(lcd_rgbunpack)
436 int rgb = luaL_checkint(L, 1);
437 lua_pushinteger(L, RGB_UNPACK_RED(rgb));
438 lua_pushinteger(L, RGB_UNPACK_GREEN(rgb));
439 lua_pushinteger(L, RGB_UNPACK_BLUE(rgb));
440 return 3;
442 #endif
444 RB_WRAP(read_bmp_file)
446 struct bitmap bm;
447 const char* filename = luaL_checkstring(L, 1);
448 bool dither = luaL_optboolean(L, 2, true);
449 bool transparent = luaL_optboolean(L, 3, false);
450 int format = FORMAT_NATIVE;
452 if(dither)
453 format |= FORMAT_DITHER;
455 if(transparent)
456 format |= FORMAT_TRANSPARENT;
458 int result = rb->read_bmp_file(filename, &bm, 0, format | FORMAT_RETURN_SIZE, NULL);
460 if(result > 0)
462 bm.data = (unsigned char*) rli_alloc(L, bm.width, bm.height);
463 rb->read_bmp_file(filename, &bm, result, format, NULL);
465 return 1;
468 return 0;
471 RB_WRAP(current_path)
473 const char *current_path = get_current_path(L, 1);
474 if(current_path != NULL)
476 lua_pushstring(L, current_path);
477 return 1;
479 else
480 return 0;
483 #define R(NAME) {#NAME, rock_##NAME}
484 static const luaL_Reg rocklib[] =
486 /* Graphics */
487 #ifdef HAVE_LCD_BITMAP
488 R(lcd_framebuffer),
489 R(lcd_mono_bitmap_part),
490 R(lcd_mono_bitmap),
491 #if LCD_DEPTH > 1
492 R(lcd_get_backdrop),
493 R(lcd_bitmap_part),
494 R(lcd_bitmap),
495 #endif
496 #if LCD_DEPTH == 16
497 R(lcd_bitmap_transparent_part),
498 R(lcd_bitmap_transparent),
499 #endif
500 #endif
501 #ifdef HAVE_LCD_COLOR
502 R(lcd_rgbpack),
503 R(lcd_rgbunpack),
504 #endif
506 /* Kernel */
507 R(current_tick),
509 /* Buttons */
510 #ifdef HAVE_TOUCHSCREEN
511 R(action_get_touchscreen_press),
512 R(touchscreen_set_mode),
513 #endif
514 R(kbd_input),
516 R(font_getstringsize),
517 R(read_bmp_file),
518 R(set_viewport),
519 R(clear_viewport),
520 R(current_path),
522 {"new_image", rli_new},
524 {NULL, NULL}
526 #undef R
527 extern const luaL_Reg rocklib_aux[];
530 #define RB_CONSTANT(x) lua_pushinteger(L, x); lua_setfield(L, -2, #x);
532 ** Open Rockbox library
534 LUALIB_API int luaopen_rock(lua_State *L)
536 luaL_register(L, LUA_ROCKLIBNAME, rocklib);
537 luaL_register(L, LUA_ROCKLIBNAME, rocklib_aux);
539 RB_CONSTANT(HZ);
541 RB_CONSTANT(LCD_WIDTH);
542 RB_CONSTANT(LCD_HEIGHT);
544 RB_CONSTANT(FONT_SYSFIXED);
545 RB_CONSTANT(FONT_UI);
547 #ifdef HAVE_TOUCHSCREEN
548 RB_CONSTANT(TOUCHSCREEN_POINT);
549 RB_CONSTANT(TOUCHSCREEN_BUTTON);
550 #endif
552 rli_init(L);
554 return 1;