nsp_texture.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. // Texture module
  2. // Copyright (C) 2015 Legimet + fgalliat (Xtase)
  3. //
  4. // This file is part of Duktape-nspire.
  5. //
  6. // Duktape-nspire is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU Lesser General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // Duktape-nspire is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Lesser General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Lesser General Public License
  17. // along with Duktape-nspire. If not, see <http://www.gnu.org/licenses/>.
  18. #include "duktape.h"
  19. #include <stdbool.h>
  20. #include <libndls.h>
  21. // =================================================
  22. #include "framebuffer.h"
  23. // =================================================
  24. static duk_ret_t nsp_texture_constructor(duk_context *ctx) {
  25. int width = duk_require_int(ctx, 0);
  26. int height = duk_require_int(ctx, 1);
  27. if (width < 1 || height < 1) {
  28. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "Width and height must be positive");
  29. }
  30. bool has_transparency;
  31. uint16_t transparent_color;
  32. if ((has_transparency = duk_is_number(ctx, 2))) {
  33. transparent_color = (uint16_t)duk_get_int(ctx, 2);
  34. }
  35. duk_push_this(ctx);
  36. duk_push_fixed_buffer(ctx, width * height * 2);
  37. duk_put_prop_string(ctx, -2, "bitmap");
  38. duk_push_int(ctx, width);
  39. duk_put_prop_string(ctx, -2, "width");
  40. duk_push_int(ctx, height);
  41. duk_put_prop_string(ctx, -2, "height");
  42. if (has_transparency) {
  43. duk_push_int(ctx, transparent_color);
  44. } else {
  45. duk_push_null(ctx);
  46. }
  47. duk_put_prop_string(ctx, -2, "transparentColor");
  48. return 0;
  49. }
  50. duk_ret_t nsp_texture_display(duk_context *ctx) {
  51. duk_push_this(ctx);
  52. duk_get_prop_string(ctx, -1, "width");
  53. int width = duk_get_int(ctx, -1);
  54. duk_pop(ctx);
  55. duk_get_prop_string(ctx, -1, "height");
  56. int height = duk_get_int(ctx, -1);
  57. duk_pop(ctx);
  58. duk_get_prop_string(ctx, -1, "transparentColor");
  59. if (width != 320 || height != 240 || !duk_is_null(ctx, -1))
  60. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "must have dimensions 230x240 without transparency");
  61. duk_pop(ctx);
  62. duk_get_prop_string(ctx, -1, "bitmap");
  63. size_t size;
  64. uint16_t *bitmap;
  65. bitmap = duk_get_buffer(ctx, -1, &size);
  66. if (bitmap == NULL || size != 320 * 240 * 2)
  67. return duk_error(ctx, DUK_ERR_ERROR, "bitmap buffer does not match with dimensions");
  68. if (has_colors)
  69. lcd_blit(bitmap, SCR_320x240_565);
  70. else {
  71. uint8_t buf[240*320/2];
  72. uint8_t r[2], g[2], b[2], c[2];
  73. for (unsigned i = 0; i < 240; i++) {
  74. for (unsigned j = 0; j < 320/2; j++) {
  75. for (unsigned k = 0; k < 2; k++) {
  76. r[k] = bitmap[i*320+2*j+k] >> 12;
  77. g[k] = (bitmap[i*320+2*j+k] >> 7) & 0xF;
  78. b[k] = (bitmap[i*320+2*j+k] >> 1) & 0xF;
  79. c[k] = (30*r[k] + 59*g[k] + 11*b[k]) / 100;
  80. }
  81. buf[i*320/2+j] = (c[0] << 4) | c[1];
  82. }
  83. }
  84. lcd_blit(buf, SCR_320x240_4);
  85. }
  86. return 0;
  87. }
  88. duk_ret_t nsp_texture_fill(duk_context *ctx) {
  89. uint16_t color = duk_require_int(ctx, 0);
  90. duk_push_this(ctx);
  91. duk_get_prop_string(ctx, -1, "bitmap");
  92. size_t size;
  93. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  94. if (bitmap == NULL)
  95. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  96. for (size_t i = 0; i < size / 2; i++) {
  97. bitmap[i] = (uint16_t)color;
  98. }
  99. return 0;
  100. }
  101. duk_ret_t nsp_texture_get_pixel(duk_context *ctx) {
  102. int x = duk_require_int(ctx, 0);
  103. int y = duk_require_int(ctx, 1);
  104. duk_push_this(ctx);
  105. duk_get_prop_string(ctx, -1, "width");
  106. int w = duk_require_int(ctx, -1);
  107. duk_pop(ctx);
  108. duk_get_prop_string(ctx, -1, "height");
  109. int h = duk_require_int(ctx, -1);
  110. duk_pop(ctx);
  111. if (w <= 0 || h <= 0)
  112. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  113. duk_get_prop_string(ctx, -1, "bitmap");
  114. size_t size;
  115. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  116. if (bitmap == NULL)
  117. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  118. if (0 <= x && x < w && 0 <= y && y < h && size >= (size_t)(w * h * 2)) {
  119. duk_push_int(ctx, bitmap[w * y + x]);
  120. return 1;
  121. } else
  122. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "coordinates out of range");
  123. }
  124. duk_ret_t nsp_texture_set_pixel(duk_context *ctx) {
  125. int x = duk_require_int(ctx, 0);
  126. int y = duk_require_int(ctx, 1);
  127. uint16_t color = duk_require_int(ctx, 2);
  128. duk_push_this(ctx);
  129. duk_get_prop_string(ctx, -1, "width");
  130. int w = duk_require_int(ctx, -1);
  131. duk_pop(ctx);
  132. duk_get_prop_string(ctx, -1, "height");
  133. int h = duk_require_int(ctx, -1);
  134. duk_pop(ctx);
  135. if (w <= 0 || h <= 0)
  136. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  137. duk_get_prop_string(ctx, -1, "bitmap");
  138. size_t size;
  139. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  140. if (bitmap == NULL)
  141. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  142. if (0 <= x && x < w && 0 <= y && y < h && size >= (size_t)(w * h * 2)) {
  143. bitmap[w * y + x] = (uint16_t)color;
  144. return 0;
  145. } else
  146. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "coordinates out of range");
  147. }
  148. // ====== Xtase drawing routines ======
  149. duk_ret_t nsp_texture_draw_line(duk_context *ctx) {
  150. int x1 = duk_require_int(ctx, 0);
  151. int y1 = duk_require_int(ctx, 1);
  152. int x2 = duk_require_int(ctx, 2);
  153. int y2 = duk_require_int(ctx, 3);
  154. uint16_t color = duk_require_int(ctx, 4);
  155. duk_push_this(ctx);
  156. duk_get_prop_string(ctx, -1, "width");
  157. int w = duk_require_int(ctx, -1);
  158. duk_pop(ctx);
  159. duk_get_prop_string(ctx, -1, "height");
  160. int h = duk_require_int(ctx, -1);
  161. duk_pop(ctx);
  162. if (w <= 0 || h <= 0)
  163. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  164. duk_get_prop_string(ctx, -1, "bitmap");
  165. size_t size;
  166. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  167. if (bitmap == NULL)
  168. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  169. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  170. fb->width = w;
  171. fb->height = h;
  172. fb->fb_size = w * h;
  173. fb->fb = bitmap;
  174. drawLine(x1,y1,x2,y2,color,fb);
  175. free(fb);
  176. return 0;
  177. }
  178. duk_ret_t nsp_texture_draw_rect(duk_context *ctx) {
  179. int x = duk_require_int(ctx, 0);
  180. int y = duk_require_int(ctx, 1);
  181. int w_ = duk_require_int(ctx, 2);
  182. int h_ = duk_require_int(ctx, 3);
  183. uint16_t color = duk_require_int(ctx, 4);
  184. duk_push_this(ctx);
  185. duk_get_prop_string(ctx, -1, "width");
  186. int w = duk_require_int(ctx, -1);
  187. duk_pop(ctx);
  188. duk_get_prop_string(ctx, -1, "height");
  189. int h = duk_require_int(ctx, -1);
  190. duk_pop(ctx);
  191. if (w <= 0 || h <= 0)
  192. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  193. duk_get_prop_string(ctx, -1, "bitmap");
  194. size_t size;
  195. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  196. if (bitmap == NULL)
  197. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  198. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  199. fb->width = w;
  200. fb->height = h;
  201. fb->fb_size = w * h;
  202. fb->fb = bitmap;
  203. drawRect(x,y,w_,h_,color,fb);
  204. free(fb);
  205. return 0;
  206. }
  207. duk_ret_t nsp_texture_fill_rect(duk_context *ctx) {
  208. int x = duk_require_int(ctx, 0);
  209. int y = duk_require_int(ctx, 1);
  210. int w_ = duk_require_int(ctx, 2);
  211. int h_ = duk_require_int(ctx, 3);
  212. uint16_t color = duk_require_int(ctx, 4);
  213. duk_push_this(ctx);
  214. duk_get_prop_string(ctx, -1, "width");
  215. int w = duk_require_int(ctx, -1);
  216. duk_pop(ctx);
  217. duk_get_prop_string(ctx, -1, "height");
  218. int h = duk_require_int(ctx, -1);
  219. duk_pop(ctx);
  220. if (w <= 0 || h <= 0)
  221. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  222. duk_get_prop_string(ctx, -1, "bitmap");
  223. size_t size;
  224. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  225. if (bitmap == NULL)
  226. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  227. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  228. fb->width = w;
  229. fb->height = h;
  230. fb->fb_size = w * h;
  231. fb->fb = bitmap;
  232. fillRect(x,y,w_,h_,color,fb);
  233. free(fb);
  234. return 0;
  235. }
  236. int* getIntArray(duk_context *ctx, int stackIndex) {
  237. static int* result = NULL;
  238. if(duk_is_array(ctx, stackIndex)) {
  239. int resultLen = duk_get_length(ctx, stackIndex);
  240. result = (int*)malloc( resultLen * sizeof(int) );
  241. memset(result,0,resultLen);
  242. duk_enum(ctx, stackIndex, DUK_ENUM_ARRAY_INDICES_ONLY);
  243. // NOT stackIndex because waits enumIndex that is -1
  244. int idx=0;
  245. while (duk_next(ctx, -1, 1)) {
  246. // in JS/duktape toto[1] <=> toto["1"]
  247. // that's why keys are strings
  248. int v = duk_to_int(ctx, -1);
  249. //printf("key=%s, value=%d\n", k, v);
  250. result[idx++] = v;
  251. duk_pop_2(ctx);
  252. }
  253. duk_pop(ctx); // duk_enum
  254. } else {
  255. printf("Found NO array\n");
  256. }
  257. return result;
  258. }
  259. duk_ret_t nsp_texture_draw_polyLines(duk_context *ctx) {
  260. duk_require_object_coercible(ctx, 0);
  261. int* xys = getIntArray(ctx,0);
  262. int nbPts = duk_require_int(ctx, 1);
  263. uint16_t color = duk_require_int(ctx, 2);
  264. duk_push_this(ctx);
  265. duk_get_prop_string(ctx, -1, "width");
  266. int w = duk_require_int(ctx, -1);
  267. duk_pop(ctx);
  268. duk_get_prop_string(ctx, -1, "height");
  269. int h = duk_require_int(ctx, -1);
  270. duk_pop(ctx);
  271. if (w <= 0 || h <= 0)
  272. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  273. duk_get_prop_string(ctx, -1, "bitmap");
  274. size_t size;
  275. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  276. if (bitmap == NULL)
  277. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  278. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  279. fb->width = w;
  280. fb->height = h;
  281. fb->fb_size = w * h;
  282. fb->fb = bitmap;
  283. drawPolyLines( xys, nbPts, color, fb );
  284. free(fb);
  285. return 0;
  286. }
  287. duk_ret_t nsp_texture_fill_polygon(duk_context *ctx) {
  288. duk_require_object_coercible(ctx, 0);
  289. int* xys = getIntArray(ctx,0);
  290. int nbPts = duk_require_int(ctx, 1);
  291. uint16_t color = duk_require_int(ctx, 2);
  292. duk_push_this(ctx);
  293. duk_get_prop_string(ctx, -1, "width");
  294. int w = duk_require_int(ctx, -1);
  295. duk_pop(ctx);
  296. duk_get_prop_string(ctx, -1, "height");
  297. int h = duk_require_int(ctx, -1);
  298. duk_pop(ctx);
  299. if (w <= 0 || h <= 0)
  300. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  301. duk_get_prop_string(ctx, -1, "bitmap");
  302. size_t size;
  303. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  304. if (bitmap == NULL)
  305. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  306. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  307. fb->width = w;
  308. fb->height = h;
  309. fb->fb_size = w * h;
  310. fb->fb = bitmap;
  311. fillPolygon( xys, nbPts, color, fb );
  312. free(fb);
  313. return 0;
  314. }
  315. duk_ret_t nsp_texture_draw_circle(duk_context *ctx) {
  316. int x = duk_require_int(ctx, 0);
  317. int y = duk_require_int(ctx, 1);
  318. int radius = duk_require_int(ctx, 2);
  319. uint16_t color = duk_require_int(ctx, 3);
  320. duk_push_this(ctx);
  321. duk_get_prop_string(ctx, -1, "width");
  322. int w = duk_require_int(ctx, -1);
  323. duk_pop(ctx);
  324. duk_get_prop_string(ctx, -1, "height");
  325. int h = duk_require_int(ctx, -1);
  326. duk_pop(ctx);
  327. if (w <= 0 || h <= 0)
  328. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  329. duk_get_prop_string(ctx, -1, "bitmap");
  330. size_t size;
  331. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  332. if (bitmap == NULL)
  333. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  334. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  335. fb->width = w;
  336. fb->height = h;
  337. fb->fb_size = w * h;
  338. fb->fb = bitmap;
  339. drawCircle(x,y,radius,color,fb);
  340. free(fb);
  341. return 0;
  342. }
  343. duk_ret_t nsp_texture_fill_circle(duk_context *ctx) {
  344. int x = duk_require_int(ctx, 0);
  345. int y = duk_require_int(ctx, 1);
  346. int radius = duk_require_int(ctx, 2);
  347. uint16_t color = duk_require_int(ctx, 3);
  348. duk_push_this(ctx);
  349. duk_get_prop_string(ctx, -1, "width");
  350. int w = duk_require_int(ctx, -1);
  351. duk_pop(ctx);
  352. duk_get_prop_string(ctx, -1, "height");
  353. int h = duk_require_int(ctx, -1);
  354. duk_pop(ctx);
  355. if (w <= 0 || h <= 0)
  356. return duk_error(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive");
  357. duk_get_prop_string(ctx, -1, "bitmap");
  358. size_t size;
  359. uint16_t *bitmap = duk_get_buffer(ctx, -1, &size);
  360. if (bitmap == NULL)
  361. return duk_error(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL");
  362. FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) );
  363. fb->width = w;
  364. fb->height = h;
  365. fb->fb_size = w * h;
  366. fb->fb = bitmap;
  367. fillCircle(x,y,radius,color,fb);
  368. free(fb);
  369. return 0;
  370. }
  371. // ======/Xtase drawing routines/======
  372. static const duk_function_list_entry nsp_texture_methods[] = {
  373. {"display", nsp_texture_display, 0},
  374. {"fill", nsp_texture_fill, 1},
  375. {"getPx", nsp_texture_get_pixel, 2},
  376. {"setPx", nsp_texture_set_pixel, 3},
  377. // Xtase drawing routines
  378. {"drawLine", nsp_texture_draw_line, 5},
  379. {"drawRect", nsp_texture_draw_rect, 5},
  380. {"fillRect", nsp_texture_fill_rect, 5},
  381. {"drawPolyLines", nsp_texture_draw_polyLines, 3},
  382. {"fillPolygon", nsp_texture_fill_polygon, 3},
  383. {"drawCircle", nsp_texture_draw_circle, 4},
  384. {"fillCircle", nsp_texture_fill_circle, 4},
  385. {NULL, NULL, 0}
  386. };
  387. duk_ret_t dukopen_nsp_texture(duk_context *ctx) {
  388. duk_idx_t idx = duk_push_object(ctx);
  389. duk_idx_t stats_constr = duk_push_c_function(ctx, nsp_texture_constructor, DUK_VARARGS);
  390. duk_idx_t stats_prot = duk_push_object(ctx);
  391. duk_put_function_list(ctx, stats_prot, nsp_texture_methods);
  392. duk_put_prop_string(ctx, stats_constr, "prototype");
  393. duk_put_prop_string(ctx, idx, "Texture");
  394. return 1;
  395. }