pixbuf.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include <string.h>
  4. #include "pixbuf.h"
  5. #define PIXBUF_METATABLE "pixbuf.buf"
  6. #ifndef MIN
  7. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  8. #endif
  9. #ifndef MAX
  10. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  11. #endif
  12. pixbuf *pixbuf_from_lua_arg(lua_State *L, int arg) {
  13. return luaL_checkudata(L, arg, PIXBUF_METATABLE);
  14. }
  15. pixbuf *pixbuf_opt_from_lua_arg(lua_State *L, int arg) {
  16. return luaL_testudata(L, arg, PIXBUF_METATABLE);
  17. }
  18. static ssize_t posrelat(ssize_t pos, size_t len) {
  19. /* relative string position: negative means back from end */
  20. if (pos < 0)
  21. pos += (ssize_t)len + 1;
  22. return MIN(MAX(pos, 1), len);
  23. }
  24. const size_t pixbuf_channels(pixbuf *p) {
  25. return p->nchan;
  26. }
  27. const size_t pixbuf_size(pixbuf *p) {
  28. return p->npix * p->nchan;
  29. }
  30. /*
  31. * Construct a pixbuf newuserdata using C arguments.
  32. *
  33. * Allocates, so may throw! Leaves new buffer at the top of the Lua stack
  34. * and returns a C pointer.
  35. */
  36. static pixbuf *pixbuf_new(lua_State *L, size_t leds, size_t chans) {
  37. // Allocate memory
  38. // A crude hack of an overflow check, but unlikely to be reached in practice
  39. if ((leds > 8192) || (chans > 32)) {
  40. luaL_error(L, "pixbuf size limits exeeded");
  41. return NULL; // UNREACHED
  42. }
  43. size_t size = sizeof(pixbuf) + leds * chans;
  44. pixbuf *buffer = (pixbuf*)lua_newuserdata(L, size);
  45. // Associate its metatable
  46. luaL_getmetatable(L, PIXBUF_METATABLE);
  47. lua_setmetatable(L, -2);
  48. // Save led strip size
  49. *(size_t *)&buffer->npix = leds;
  50. *(size_t *)&buffer->nchan = chans;
  51. memset(buffer->values, 0, leds * chans);
  52. return buffer;
  53. }
  54. // Handle a buffer where we can store led values
  55. int pixbuf_new_lua(lua_State *L) {
  56. const int leds = luaL_checkint(L, 1);
  57. const int chans = luaL_checkint(L, 2);
  58. luaL_argcheck(L, leds > 0, 1, "should be a positive integer");
  59. luaL_argcheck(L, chans > 0, 2, "should be a positive integer");
  60. pixbuf_new(L, leds, chans);
  61. return 1;
  62. }
  63. static int pixbuf_concat_lua(lua_State *L) {
  64. pixbuf *lhs = pixbuf_from_lua_arg(L, 1);
  65. pixbuf *rhs = pixbuf_from_lua_arg(L, 2);
  66. luaL_argcheck(L, lhs->nchan == rhs->nchan, 1,
  67. "can only concatenate buffers with same channel count");
  68. size_t osize = lhs->npix + rhs->npix;
  69. if (lhs->npix > osize) {
  70. return luaL_error(L, "size sum overflow");
  71. }
  72. pixbuf *buffer = pixbuf_new(L, osize, lhs->nchan);
  73. memcpy(buffer->values, lhs->values, pixbuf_size(lhs));
  74. memcpy(buffer->values + pixbuf_size(lhs), rhs->values, pixbuf_size(rhs));
  75. return 1;
  76. }
  77. static int pixbuf_channels_lua(lua_State *L) {
  78. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  79. lua_pushinteger(L, buffer->nchan);
  80. return 1;
  81. }
  82. static int pixbuf_dump_lua(lua_State *L) {
  83. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  84. lua_pushlstring(L, (char*)buffer->values, pixbuf_size(buffer));
  85. return 1;
  86. }
  87. static int pixbuf_eq_lua(lua_State *L) {
  88. bool res;
  89. pixbuf *lhs = pixbuf_from_lua_arg(L, 1);
  90. pixbuf *rhs = pixbuf_from_lua_arg(L, 2);
  91. if (lhs->npix != rhs->npix) {
  92. res = false;
  93. } else if (lhs->nchan != rhs->nchan) {
  94. res = false;
  95. } else {
  96. res = true;
  97. for(size_t i = 0; i < pixbuf_size(lhs); i++) {
  98. if(lhs->values[i] != rhs->values[i]) {
  99. res = false;
  100. break;
  101. }
  102. }
  103. }
  104. lua_pushboolean(L, res);
  105. return 1;
  106. }
  107. static int pixbuf_fade_lua(lua_State *L) {
  108. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  109. const int fade = luaL_checkinteger(L, 2);
  110. unsigned direction = luaL_optinteger( L, 3, PIXBUF_FADE_OUT );
  111. luaL_argcheck(L, fade > 0, 2, "fade value should be a strictly positive int");
  112. uint8_t *p = &buffer->values[0];
  113. for (size_t i = 0; i < pixbuf_size(buffer); i++)
  114. {
  115. if (direction == PIXBUF_FADE_OUT)
  116. {
  117. *p++ /= fade;
  118. }
  119. else
  120. {
  121. // as fade in can result in value overflow, an int is used to perform the check afterwards
  122. int val = *p * fade;
  123. *p++ = MIN(255, val);
  124. }
  125. }
  126. return 0;
  127. }
  128. /* Fade an Ixxx-type strip by just manipulating the I bytes */
  129. static int pixbuf_fadeI_lua(lua_State *L) {
  130. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  131. const int fade = luaL_checkinteger(L, 2);
  132. unsigned direction = luaL_optinteger( L, 3, PIXBUF_FADE_OUT );
  133. luaL_argcheck(L, fade > 0, 2, "fade value should be a strictly positive int");
  134. uint8_t *p = &buffer->values[0];
  135. for (size_t i = 0; i < buffer->npix; i++, p+=buffer->nchan) {
  136. if (direction == PIXBUF_FADE_OUT) {
  137. *p /= fade;
  138. } else {
  139. int val = *p * fade;
  140. *p++ = MIN(255, val);
  141. }
  142. }
  143. return 0;
  144. }
  145. static int pixbuf_fill_lua(lua_State *L) {
  146. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  147. if (buffer->npix == 0) {
  148. goto out;
  149. }
  150. if (lua_gettop(L) != (1 + buffer->nchan)) {
  151. return luaL_argerror(L, 1, "need as many values as colors per pixel");
  152. }
  153. /* Fill the first pixel from the Lua stack */
  154. for (size_t i = 0; i < buffer->nchan; i++) {
  155. buffer->values[i] = luaL_checkinteger(L, 2+i);
  156. }
  157. /* Fill the rest of the pixels from the first */
  158. for (size_t i = 1; i < buffer->npix; i++) {
  159. memcpy(&buffer->values[i * buffer->nchan], buffer->values, buffer->nchan);
  160. }
  161. out:
  162. lua_settop(L, 1);
  163. return 1;
  164. }
  165. static int pixbuf_get_lua(lua_State *L) {
  166. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  167. const int led = luaL_checkinteger(L, 2) - 1;
  168. size_t channels = buffer->nchan;
  169. luaL_argcheck(L, led >= 0 && led < buffer->npix, 2, "index out of range");
  170. uint8_t tmp[channels];
  171. memcpy(tmp, &buffer->values[channels*led], channels);
  172. for (size_t i = 0; i < channels; i++)
  173. {
  174. lua_pushinteger(L, tmp[i]);
  175. }
  176. return channels;
  177. }
  178. /* :map(f, buf1, ilo, ihi, [buf2, ilo2]) */
  179. static int pixbuf_map_lua(lua_State *L) {
  180. pixbuf *outbuf = pixbuf_from_lua_arg(L, 1);
  181. /* f at index 2 */
  182. pixbuf *buffer1 = pixbuf_opt_from_lua_arg(L, 3);
  183. if (!buffer1)
  184. buffer1 = outbuf;
  185. const int ilo = posrelat(luaL_optinteger(L, 4, 1), buffer1->npix) - 1;
  186. const int ihi = posrelat(luaL_optinteger(L, 5, buffer1->npix), buffer1->npix) - 1;
  187. luaL_argcheck(L, ihi > ilo, 3, "Buffer limits out of order");
  188. size_t npix = ihi - ilo + 1;
  189. luaL_argcheck(L, npix == outbuf->npix, 1, "Output buffer wrong size");
  190. pixbuf *buffer2 = pixbuf_opt_from_lua_arg(L, 6);
  191. const int ilo2 = buffer2 ? posrelat(luaL_optinteger(L, 7, 1), buffer2->npix) - 1 : 0;
  192. if (buffer2) {
  193. luaL_argcheck(L, ilo2 + npix <= buffer2->npix, 6, "Second buffer too short");
  194. }
  195. for (size_t p = 0; p < npix; p++) {
  196. lua_pushvalue(L, 2);
  197. for (size_t c = 0; c < buffer1->nchan; c++) {
  198. lua_pushinteger(L, buffer1->values[(ilo + p) * buffer1->nchan + c]);
  199. }
  200. if (buffer2) {
  201. for (size_t c = 0; c < buffer2->nchan; c++) {
  202. lua_pushinteger(L, buffer2->values[(ilo2 + p) * buffer2->nchan + c]);
  203. }
  204. }
  205. lua_call(L, buffer1->nchan + (buffer2 ? buffer2->nchan : 0), outbuf->nchan);
  206. for (size_t c = 0; c < outbuf->nchan; c++) {
  207. outbuf->values[(p + 1) * outbuf->nchan - c - 1] = luaL_checkinteger(L, -1);
  208. lua_pop(L, 1);
  209. }
  210. }
  211. lua_settop(L, 1);
  212. return 1;
  213. }
  214. struct mix_source {
  215. int factor;
  216. const uint8_t *values;
  217. };
  218. static uint32_t pixbuf_mix_clamp(int32_t v) {
  219. if (v < 0) { return 0; }
  220. if (v > 255) { return 255; }
  221. return v;
  222. }
  223. /* This one can sum straightforwardly, channel by channel */
  224. static void pixbuf_mix_raw(pixbuf *out, size_t n_src, struct mix_source* src) {
  225. size_t cells = pixbuf_size(out);
  226. for (size_t c = 0; c < cells; c++) {
  227. int32_t val = 0;
  228. for (size_t s = 0; s < n_src; s++) {
  229. val += (int32_t)src[s].values[c] * src[s].factor;
  230. }
  231. val += 128; // rounding instead of floor
  232. val /= 256; // do not use implemetation dependant right shift
  233. out->values[c] = (uint8_t)pixbuf_mix_clamp(val);
  234. }
  235. }
  236. /* Mix intensity-mediated three-color pixbufs.
  237. *
  238. * XXX This is untested in real hardware; do they actually behave like this?
  239. */
  240. static void pixbuf_mix_i3(pixbuf *out, size_t ibits, size_t n_src,
  241. struct mix_source* src) {
  242. for(size_t p = 0; p < out->npix; p++) {
  243. int32_t sums[3] = { 0, 0, 0 };
  244. for (size_t s = 0; s < n_src; s++) {
  245. for (size_t c = 0; c < 3; c++) {
  246. sums[c] += (int32_t)src[s].values[4*p+c+1] // color channel
  247. * src[s].values[4*p] // global intensity
  248. * src[s].factor; // user factor
  249. }
  250. }
  251. uint32_t pmaxc = 0;
  252. for (size_t c = 0; c < 3; c++) {
  253. pmaxc = sums[c] > pmaxc ? sums[c] : pmaxc;
  254. }
  255. size_t maxgi;
  256. if (pmaxc == 0) {
  257. /* Zero value */
  258. memset(&out->values[4*p], 0, 4);
  259. return;
  260. } else if (pmaxc <= (1 << 16)) {
  261. /* Minimum global factor */
  262. maxgi = 1;
  263. } else if (pmaxc >= ((1 << ibits) - 1) << 16) {
  264. /* Maximum global factor */
  265. maxgi = (1 << ibits) - 1;
  266. } else {
  267. maxgi = (pmaxc >> 16) + 1;
  268. }
  269. // printf("mixi3: %x %x %x -> %x, %zx\n", sums[0], sums[1], sums[2], pmaxc, maxgi);
  270. out->values[4*p] = maxgi;
  271. for (size_t c = 0; c < 3; c++) {
  272. out->values[4*p+c+1] = pixbuf_mix_clamp((sums[c] + 256 * maxgi - 127) / (256 * maxgi));
  273. }
  274. }
  275. }
  276. // buffer:mix(factor1, buffer1, ..)
  277. // factor is 256 for 100%
  278. // uses saturating arithmetic (one buffer at a time)
  279. static int pixbuf_mix_core(lua_State *L, size_t ibits) {
  280. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  281. pixbuf *src_buffer;
  282. int pos = 2;
  283. size_t n_sources = (lua_gettop(L) - 1) / 2;
  284. struct mix_source sources[n_sources];
  285. if (n_sources == 0) {
  286. lua_settop(L, 1);
  287. return 1;
  288. }
  289. for (size_t src = 0; src < n_sources; src++, pos += 2) {
  290. int factor = luaL_checkinteger(L, pos);
  291. src_buffer = pixbuf_from_lua_arg(L, pos + 1);
  292. luaL_argcheck(L, src_buffer->npix == buffer->npix &&
  293. src_buffer->nchan == buffer->nchan,
  294. pos + 1, "buffer not same size or shape");
  295. sources[src].factor = factor;
  296. sources[src].values = src_buffer->values;
  297. }
  298. if (ibits != 0) {
  299. luaL_argcheck(L, src_buffer->nchan == 4, 2, "Requires 4 channel pixbuf");
  300. pixbuf_mix_i3(buffer, ibits, n_sources, sources);
  301. } else {
  302. pixbuf_mix_raw(buffer, n_sources, sources);
  303. }
  304. lua_settop(L, 1);
  305. return 1;
  306. }
  307. static int pixbuf_mix_lua(lua_State *L) {
  308. return pixbuf_mix_core(L, 0);
  309. }
  310. static int pixbuf_mix4I5_lua(lua_State *L) {
  311. return pixbuf_mix_core(L, 5);
  312. }
  313. // Returns the total of all channels
  314. static int pixbuf_power_lua(lua_State *L) {
  315. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  316. int total = 0;
  317. size_t p = 0;
  318. for (size_t i = 0; i < buffer->npix; i++) {
  319. for (size_t j = 0; j < buffer->nchan; j++, p++) {
  320. total += buffer->values[p];
  321. }
  322. }
  323. lua_pushinteger(L, total);
  324. return 1;
  325. }
  326. // Returns the total of all channels, intensity-style
  327. static int pixbuf_powerI_lua(lua_State *L) {
  328. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  329. int total = 0;
  330. size_t p = 0;
  331. for (size_t i = 0; i < buffer->npix; i++) {
  332. int inten = buffer->values[p++];
  333. for (size_t j = 0; j < buffer->nchan - 1; j++, p++) {
  334. total += inten * buffer->values[p];
  335. }
  336. }
  337. lua_pushinteger(L, total);
  338. return 1;
  339. }
  340. static int pixbuf_replace_lua(lua_State *L) {
  341. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  342. ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), buffer->npix);
  343. size_t channels = buffer->nchan;
  344. uint8_t *src;
  345. size_t srcLen;
  346. if (lua_type(L, 2) == LUA_TSTRING) {
  347. size_t length;
  348. src = (uint8_t *) lua_tolstring(L, 2, &length);
  349. srcLen = length / channels;
  350. } else {
  351. pixbuf *rhs = pixbuf_from_lua_arg(L, 2);
  352. luaL_argcheck(L, rhs->nchan == buffer->nchan, 2, "buffers have different channels");
  353. src = rhs->values;
  354. srcLen = rhs->npix;
  355. }
  356. luaL_argcheck(L, srcLen + start - 1 <= buffer->npix, 2, "does not fit into destination");
  357. memcpy(buffer->values + (start - 1) * channels, src, srcLen * channels);
  358. return 0;
  359. }
  360. static int pixbuf_set_lua(lua_State *L) {
  361. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  362. const int led = luaL_checkinteger(L, 2) - 1;
  363. const size_t channels = buffer->nchan;
  364. luaL_argcheck(L, led >= 0 && led < buffer->npix, 2, "index out of range");
  365. int type = lua_type(L, 3);
  366. if(type == LUA_TTABLE)
  367. {
  368. for (size_t i = 0; i < channels; i++)
  369. {
  370. lua_rawgeti(L, 3, i+1);
  371. buffer->values[channels*led+i] = lua_tointeger(L, -1);
  372. lua_pop(L, 1);
  373. }
  374. }
  375. else if(type == LUA_TSTRING)
  376. {
  377. size_t len;
  378. const char *buf = lua_tolstring(L, 3, &len);
  379. // Overflow check
  380. if( channels*led + len > channels*buffer->npix ) {
  381. return luaL_error(L, "string size will exceed strip length");
  382. }
  383. if ( len % channels != 0 ) {
  384. return luaL_error(L, "string does not contain whole LEDs");
  385. }
  386. memcpy(&buffer->values[channels*led], buf, len);
  387. }
  388. else
  389. {
  390. luaL_argcheck(L, lua_gettop(L) <= 2 + channels, 2 + channels,
  391. "extra values given");
  392. for (size_t i = 0; i < channels; i++)
  393. {
  394. buffer->values[channels*led+i] = luaL_checkinteger(L, 3+i);
  395. }
  396. }
  397. lua_settop(L, 1);
  398. return 1;
  399. }
  400. static void pixbuf_shift_circular(pixbuf *buffer, struct pixbuf_shift_params *sp) {
  401. /* Move a buffer of pixels per iteration; loop repeatedly if needed */
  402. uint8_t tmpbuf[32];
  403. uint8_t *v = buffer->values;
  404. size_t shiftRemaining = sp->shift;
  405. size_t cursor = sp->offset;
  406. do {
  407. size_t shiftNow = MIN(shiftRemaining, sizeof tmpbuf);
  408. if (sp->shiftLeft) {
  409. memcpy(tmpbuf, &v[cursor], shiftNow);
  410. memmove(&v[cursor], &v[cursor+shiftNow], sp->window - shiftNow);
  411. memcpy(&v[cursor+sp->window-shiftNow], tmpbuf, shiftNow);
  412. } else {
  413. memcpy(tmpbuf, &v[cursor+sp->window-shiftNow], shiftNow);
  414. memmove(&v[cursor+shiftNow], &v[cursor], sp->window - shiftNow);
  415. memcpy(&v[cursor], tmpbuf, shiftNow);
  416. }
  417. cursor += shiftNow;
  418. shiftRemaining -= shiftNow;
  419. } while(shiftRemaining > 0);
  420. }
  421. static void pixbuf_shift_logical(pixbuf *buffer, struct pixbuf_shift_params *sp) {
  422. /* Logical shifts don't require a temporary buffer, so we just move bytes */
  423. uint8_t *v = buffer->values;
  424. if (sp->shiftLeft) {
  425. memmove(&v[sp->offset], &v[sp->offset+sp->shift], sp->window - sp->shift);
  426. bzero(&v[sp->offset+sp->window-sp->shift], sp->shift);
  427. } else {
  428. memmove(&v[sp->offset+sp->shift], &v[sp->offset], sp->window - sp->shift);
  429. bzero(&v[sp->offset], sp->shift);
  430. }
  431. }
  432. void pixbuf_shift(pixbuf *b, struct pixbuf_shift_params *sp) {
  433. #if 0
  434. printf("Pixbuf %p shifting %s %s by %zd from %zd with window %zd\n",
  435. b,
  436. sp->shiftLeft ? "left" : "right",
  437. sp->type == PIXBUF_SHIFT_LOGICAL ? "logically" : "circularly",
  438. sp->shift, sp->offset, sp->window);
  439. #endif
  440. switch(sp->type) {
  441. case PIXBUF_SHIFT_LOGICAL: return pixbuf_shift_logical(b, sp);
  442. case PIXBUF_SHIFT_CIRCULAR: return pixbuf_shift_circular(b, sp);
  443. }
  444. }
  445. int pixbuf_shift_lua(lua_State *L) {
  446. struct pixbuf_shift_params sp;
  447. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  448. const int shift_shift = luaL_checkinteger(L, 2) * buffer->nchan;
  449. const unsigned shift_type = luaL_optinteger(L, 3, PIXBUF_SHIFT_LOGICAL);
  450. const int pos_start = posrelat(luaL_optinteger(L, 4, 1), buffer->npix);
  451. const int pos_end = posrelat(luaL_optinteger(L, 5, -1), buffer->npix);
  452. if (shift_shift < 0) {
  453. sp.shiftLeft = true;
  454. sp.shift = -shift_shift;
  455. } else {
  456. sp.shiftLeft = false;
  457. sp.shift = shift_shift;
  458. }
  459. switch(shift_type) {
  460. case PIXBUF_SHIFT_LOGICAL:
  461. case PIXBUF_SHIFT_CIRCULAR:
  462. sp.type = shift_type;
  463. break;
  464. default:
  465. return luaL_argerror(L, 3, "invalid shift type");
  466. }
  467. if (pos_start < 1) {
  468. return luaL_argerror(L, 4, "start position must be >= 1");
  469. }
  470. if (pos_end < pos_start) {
  471. return luaL_argerror(L, 5, "end position must be >= start");
  472. }
  473. sp.offset = (pos_start - 1) * buffer->nchan;
  474. sp.window = (pos_end - pos_start + 1) * buffer->nchan;
  475. if (sp.shift > pixbuf_size(buffer)) {
  476. return luaL_argerror(L, 2, "shifting more elements than buffer size");
  477. }
  478. if (sp.shift > sp.window) {
  479. return luaL_argerror(L, 2, "shifting more than sliced window");
  480. }
  481. pixbuf_shift(buffer, &sp);
  482. return 0;
  483. }
  484. /* XXX for backwards-compat with ws2812_effects; deprecated and should be removed */
  485. void pixbuf_prepare_shift(pixbuf *buffer, struct pixbuf_shift_params *sp,
  486. int shift, enum pixbuf_shift type, int start, int end)
  487. {
  488. start = posrelat(start, buffer->npix);
  489. end = posrelat(end, buffer->npix);
  490. lua_assert((end > start) && (start > 0) && (end < buffer->npix));
  491. sp->type = type;
  492. sp->offset = (start - 1) * buffer->nchan;
  493. sp->window = (end - start + 1) * buffer->nchan;
  494. if (shift < 0) {
  495. sp->shiftLeft = true;
  496. sp->shift = -shift * buffer->nchan;
  497. } else {
  498. sp->shiftLeft = false;
  499. sp->shift = shift * buffer->nchan;
  500. }
  501. }
  502. static int pixbuf_size_lua(lua_State *L) {
  503. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  504. lua_pushinteger(L, buffer->npix);
  505. return 1;
  506. }
  507. static int pixbuf_sub_lua(lua_State *L) {
  508. pixbuf *lhs = pixbuf_from_lua_arg(L, 1);
  509. size_t l = lhs->npix;
  510. ssize_t start = posrelat(luaL_checkinteger(L, 2), l);
  511. ssize_t end = posrelat(luaL_optinteger(L, 3, -1), l);
  512. if (start <= end) {
  513. pixbuf *result = pixbuf_new(L, end - start + 1, lhs->nchan);
  514. memcpy(result->values, lhs->values + lhs->nchan * (start - 1),
  515. lhs->nchan * (end - start + 1));
  516. return 1;
  517. } else {
  518. pixbuf_new(L, 0, lhs->nchan);
  519. return 1;
  520. }
  521. }
  522. static int pixbuf_tostring_lua(lua_State *L) {
  523. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  524. luaL_Buffer result;
  525. luaL_buffinit(L, &result);
  526. luaL_addchar(&result, '[');
  527. int p = 0;
  528. for (size_t i = 0; i < buffer->npix; i++) {
  529. if (i > 0) {
  530. luaL_addchar(&result, ',');
  531. }
  532. luaL_addchar(&result, '(');
  533. for (size_t j = 0; j < buffer->nchan; j++, p++) {
  534. if (j > 0) {
  535. luaL_addchar(&result, ',');
  536. }
  537. char numbuf[5];
  538. sprintf(numbuf, "%d", buffer->values[p]);
  539. luaL_addstring(&result, numbuf);
  540. }
  541. luaL_addchar(&result, ')');
  542. }
  543. luaL_addchar(&result, ']');
  544. luaL_pushresult(&result);
  545. return 1;
  546. }
  547. LROT_BEGIN(pixbuf_map, NULL, LROT_MASK_INDEX | LROT_MASK_EQ)
  548. LROT_TABENTRY ( __index, pixbuf_map )
  549. LROT_FUNCENTRY( __eq, pixbuf_eq_lua )
  550. LROT_FUNCENTRY( __concat, pixbuf_concat_lua )
  551. LROT_FUNCENTRY( __tostring, pixbuf_tostring_lua )
  552. LROT_FUNCENTRY( channels, pixbuf_channels_lua )
  553. LROT_FUNCENTRY( dump, pixbuf_dump_lua )
  554. LROT_FUNCENTRY( fade, pixbuf_fade_lua )
  555. LROT_FUNCENTRY( fadeI, pixbuf_fadeI_lua )
  556. LROT_FUNCENTRY( fill, pixbuf_fill_lua )
  557. LROT_FUNCENTRY( get, pixbuf_get_lua )
  558. LROT_FUNCENTRY( replace, pixbuf_replace_lua )
  559. LROT_FUNCENTRY( map, pixbuf_map_lua )
  560. LROT_FUNCENTRY( mix, pixbuf_mix_lua )
  561. LROT_FUNCENTRY( mix4I5, pixbuf_mix4I5_lua )
  562. LROT_FUNCENTRY( power, pixbuf_power_lua )
  563. LROT_FUNCENTRY( powerI, pixbuf_powerI_lua )
  564. LROT_FUNCENTRY( set, pixbuf_set_lua )
  565. LROT_FUNCENTRY( shift, pixbuf_shift_lua )
  566. LROT_FUNCENTRY( size, pixbuf_size_lua )
  567. LROT_FUNCENTRY( sub, pixbuf_sub_lua )
  568. LROT_END(pixbuf_map, NULL, LROT_MASK_INDEX | LROT_MASK_EQ)
  569. LROT_BEGIN(pixbuf, NULL, 0)
  570. LROT_NUMENTRY( FADE_IN, PIXBUF_FADE_IN )
  571. LROT_NUMENTRY( FADE_OUT, PIXBUF_FADE_OUT )
  572. LROT_NUMENTRY( SHIFT_CIRCULAR, PIXBUF_SHIFT_CIRCULAR )
  573. LROT_NUMENTRY( SHIFT_LOGICAL, PIXBUF_SHIFT_LOGICAL )
  574. LROT_FUNCENTRY( newBuffer, pixbuf_new_lua )
  575. LROT_END(pixbuf, NULL, 0)
  576. int luaopen_pixbuf(lua_State *L) {
  577. luaL_rometatable(L, PIXBUF_METATABLE, LROT_TABLEREF(pixbuf_map));
  578. lua_pushrotable(L, LROT_TABLEREF(pixbuf));
  579. return 1;
  580. }
  581. NODEMCU_MODULE(PIXBUF, "pixbuf", pixbuf, luaopen_pixbuf);