1 /*
2 * Copyright 2009-2021 Peter Kosyh <p.kosyh at gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25 #include "externals.h"
26 #include "internals.h"
27 #include "noise1234.h"
28
29 static LIST_HEAD(sprites);
30
31 static LIST_HEAD(fonts);
32
33 #define FN_SCALED 1
34
35 typedef struct {
36 struct list_node list;
37 char *name;
38 int flags;
39 fnt_t fnt;
40 } _fnt_t;
41
42 typedef struct {
43 struct list_node list;
44 char *name;
45 img_t img;
46 } _spr_t;
47
48 struct lua_pixels;
49
50 static img_t pixels_img(struct lua_pixels *hdr);
51
sprites_free(void)52 static void sprites_free(void)
53 {
54 /* fprintf(stderr, "sprites free \n"); */
55 while (!list_empty(&sprites)) {
56 _spr_t *sp = list_top(&sprites, _spr_t, list);
57 free(sp->name);
58 cache_forget(gfx_image_cache(), sp->img);
59 list_del(&sp->list);
60 free(sp);
61 }
62 while (!list_empty(&fonts)) {
63 _fnt_t *fn = list_top(&fonts, _fnt_t, list);
64 fnt_free(fn->fnt);
65 free(fn->name);
66 list_del(&fn->list);
67 free(fn);
68 }
69 game_pict_modify(NULL);
70 cache_shrink(gfx_image_cache());
71 }
72
sprite_lookup(const char * name)73 static _spr_t *sprite_lookup(const char *name)
74 {
75 _spr_t *pos = NULL;
76 _spr_t *sp;
77 list_for_each(&sprites, pos, list) {
78 sp = (_spr_t*)pos;
79 if (!strcmp(name, sp->name)) {
80 list_del(&sp->list);
81 list_add(&sprites, &sp->list); /* move it on head */
82 return sp;
83 }
84 }
85 return NULL;
86 }
87
font_lookup(const char * name)88 static _fnt_t *font_lookup(const char *name)
89 {
90 _fnt_t *pos = NULL;
91 _fnt_t *fn;
92 list_for_each(&fonts, pos, list) {
93 fn = (_fnt_t*)pos;
94 if (!strcmp(name, fn->name)) {
95 list_del(&fn->list);
96 list_add(&fonts, &fn->list); /* move it on head */
97 return fn;
98 }
99 }
100 return NULL;
101 }
102
sprite_new(const char * name,img_t img)103 static _spr_t *sprite_new(const char *name, img_t img)
104 {
105 _spr_t *sp;
106 sp = malloc(sizeof(_spr_t));
107 if (!sp)
108 return NULL;
109 /* INIT_LIST_HEAD(&sp->list); */
110 sp->name = strdup(name);
111 if (!sp->name) {
112 free(sp);
113 return NULL;
114 }
115 sp->img = img;
116 if (cache_add(gfx_image_cache(), name, img)) {
117 free(sp->name);
118 free(sp);
119 return NULL;
120 }
121 /* fprintf(stderr, "added: %s\n", name); */
122 list_add(&sprites, &sp->list);
123 return sp;
124 }
125
font_new(const char * name,fnt_t fnt)126 static _fnt_t *font_new(const char *name, fnt_t fnt)
127 {
128 _fnt_t *fn;
129 fn = malloc(sizeof(_fnt_t));
130 if (!fn)
131 return NULL;
132 /* INIT_LIST_HEAD(&fn->list); */
133 fn->name = strdup(name);
134 if (!fn->name) {
135 free(fn);
136 return NULL;
137 }
138 fn->fnt = fnt;
139 fn->flags = 0;
140 list_add(&fonts, &fn->list);
141 return fn;
142 }
143
sprite_name(const char * name,char * sname,int size)144 static void sprite_name(const char *name, char *sname, int size)
145 {
146 unsigned long h = 0;
147 if (!sname || !size)
148 return;
149 h = hash_string(name);
150 do { /* new uniq name */
151 snprintf(sname, size, "spr:%lx", h);
152 h ++;
153 } while (sprite_lookup(sname) || cache_lookup(gfx_image_cache(), sname));
154 sname[size - 1] = 0;
155 }
156
font_name(const char * name,char * sname,int size)157 static void font_name(const char *name, char *sname, int size)
158 {
159 unsigned long h = 0;
160 if (!sname || !size)
161 return;
162 h = hash_string(name);
163 do { /* new uniq name */
164 snprintf(sname, size, "fnt:%lx", h);
165 h ++;
166 } while (font_lookup(sname));
167 sname[size - 1] = 0;
168 }
169
170 static int _free_sprite(const char *key);
171
luaB_free_sprites(lua_State * L)172 static int luaB_free_sprites(lua_State *L) {
173 sprites_free();
174 return 0;
175 }
176
177 #define PIXELS_MAGIC 0x1980
178 struct lua_pixels {
179 int type;
180 int w;
181 int h;
182 float scale;
183 size_t size;
184 img_t img;
185 int dirty;
186 int direct;
187 };
188
luaB_load_sprite(lua_State * L)189 static int luaB_load_sprite(lua_State *L) {
190 int convert = 0;
191 img_t img = NULL;
192 _spr_t *sp;
193 const char *key;
194 char sname[sizeof(unsigned long) * 2 + 16];
195 struct lua_pixels *pixels = lua_touserdata(L, 1);
196 const char *desc = NULL;
197 const char *fname = NULL;
198 char pixels_name[32];
199 if (lua_isstring(L, 2))
200 desc = luaL_optstring(L, 2, NULL);
201 if (!pixels)
202 fname = luaL_optstring(L, 1, NULL);
203 else {
204 snprintf(pixels_name, sizeof(pixels_name), "pxl:%p", pixels);
205 pixels_name[sizeof(pixels_name) - 1] = 0;
206 fname = pixels_name;
207 }
208
209 if (!fname)
210 return 0;
211
212 if (pixels) {
213 if (lua_isboolean(L, 2)) {
214 convert = lua_toboolean(L, 2);
215 desc = luaL_optstring(L, 3, NULL);
216 }
217 if (convert) { /* slow path */
218 img = gfx_new_from(pixels->w, pixels->h, (unsigned char*)(pixels + 1));
219 if (img)
220 theme_gfx_scale(&img, pixels->scale);
221 } else {
222 img = pixels_img(pixels);
223 if (img)
224 img = gfx_dup(img);
225 }
226 } else {
227 img = gfx_load_image((char*)fname);
228 if (img)
229 theme_gfx_scale(&img, 1.0f);
230 }
231 if (img)
232 img = gfx_display_alpha(img); /*speed up */
233
234 if (!img)
235 goto err;
236
237 if (!desc || sprite_lookup(desc)) {
238 key = sname;
239 sprite_name(fname, sname, sizeof(sname));
240 } else
241 key = desc;
242 sp = sprite_new(key, img);
243 if (!sp)
244 goto err;
245
246 lua_pushstring(L, key);
247 return 1;
248 err:
249 game_res_err_msg(fname, debug_sw);
250 gfx_free_image(img);
251 return 0;
252 }
253
luaB_load_font(lua_State * L)254 static int luaB_load_font(lua_State *L) {
255 int scaled = 0;
256 fnt_t fnt = NULL;
257 _fnt_t *fn;
258 const char *key;
259 char sname[sizeof(unsigned long) * 2 + 16];
260 struct game_theme *t = &game_theme;
261
262 const char *fname = luaL_optstring(L, 1, NULL);
263 int sz = luaL_optnumber(L, 2, t->font_size);
264 const char *desc = luaL_optstring(L, 3, NULL);
265 if (!fname || sz == 0)
266 return 0;
267 if (sz > 0) {
268 sz *= game_theme.scale;
269 scaled = 1;
270 } else
271 sz = - sz; /* sz < 0 is unscalable */
272 fnt = fnt_load((char*)fname, sz);
273
274 if (!fnt)
275 return 0;
276
277 if (!desc || font_lookup(desc)) {
278 key = sname;
279 font_name(fname, sname, sizeof(sname));
280 } else
281 key = desc;
282
283 fn = font_new(key, fnt);
284 if (!fn)
285 goto err;
286
287 if (scaled)
288 fn->flags |= FN_SCALED;
289
290 lua_pushstring(L, key);
291 return 1;
292 err:
293 fnt_free(fnt);
294 return 0;
295 }
296
luaB_text_size(lua_State * L)297 static int luaB_text_size(lua_State *L) {
298 _fnt_t *fn;
299 int w = 0, h = 0;
300
301 const char *font = luaL_optstring(L, 1, NULL);
302 const char *text = luaL_optstring(L, 2, NULL);
303 int style = luaL_optnumber(L, 3, 0);
304
305 if (!font)
306 return 0;
307
308 fn = font_lookup(font);
309
310 if (!fn)
311 return 0;
312 if (!text) {
313 w = 0;
314 if (fn->flags & FN_SCALED)
315 h = ceil((float)fnt_height(fn->fnt) / game_theme.scale);
316 else
317 h = fnt_height(fn->fnt);
318 } else {
319 fnt_style(fn->fnt, style);
320 txt_size(fn->fnt, text, &w, &h);
321 if (fn->flags & FN_SCALED) {
322 w = ceil((float)w / game_theme.scale);
323 h = ceil((float)h / game_theme.scale);
324 }
325 }
326 lua_pushinteger(L, w);
327 lua_pushinteger(L, h);
328 return 2;
329 }
330
luaB_font_size_scaled(lua_State * L)331 static int luaB_font_size_scaled(lua_State *L) {
332 int sz = luaL_optnumber(L, 1, game_theme.font_size);
333 lua_pushinteger(L, FONT_SZ(sz));
334 return 1;
335 }
336
luaB_text_sprite(lua_State * L)337 static int luaB_text_sprite(lua_State *L) {
338 img_t img = NULL;
339 _spr_t *sp;
340 _fnt_t *fn;
341 const char *key;
342 char sname[sizeof(unsigned long) * 2 + 16];
343
344 const char *font = luaL_optstring(L, 1, NULL);
345 const char *text = luaL_optstring(L, 2, NULL);
346 char txtkey[32];
347 const char *color = luaL_optstring(L, 3, NULL);
348 int style = luaL_optnumber(L, 4, 0);
349 const char *desc = luaL_optstring(L, 5, NULL);
350
351 color_t col = { .r = game_theme.fgcol.r, .g = game_theme.fgcol.g, .b = game_theme.fgcol.b };
352
353 if (!font)
354 return 0;
355 if (color)
356 gfx_parse_color (color, &col);
357 if (!text)
358 text = "";
359
360 fn = font_lookup(font);
361
362 if (!fn)
363 return 0;
364
365 fnt_style(fn->fnt, style);
366
367 img = fnt_render(fn->fnt, text, col);
368
369 if (img)
370 img = gfx_display_alpha(img); /*speed up */
371
372 if (!img)
373 return 0;
374
375 if (!desc || sprite_lookup(desc)) {
376 key = sname;
377 strncpy(txtkey, text, sizeof(txtkey));
378 txtkey[sizeof(txtkey) - 1] = 0;
379 sprite_name(txtkey, sname, sizeof(sname));
380 } else
381 key = desc;
382
383 sp = sprite_new(key, img);
384
385 if (!sp)
386 goto err;
387
388 lua_pushstring(L, key);
389 return 1;
390 err:
391 gfx_free_image(img);
392 return 0;
393 }
394
395 static int in_callback = 0;
396
grab_sprite(const char * dst,int * xoff,int * yoff)397 static img_t grab_sprite(const char *dst, int *xoff, int *yoff)
398 {
399 img_t oldscreen;
400 img_t d;
401 if (!dst)
402 return NULL;
403 if ((DIRECT_MODE || in_callback) && !strcmp(dst, "screen")) {
404 d = gfx_screen(NULL);
405 *xoff = game_theme.xoff;
406 *yoff = game_theme.yoff;
407 } else if (opt_owntheme && !strcmp(dst, "screen")) {
408 if (!game_theme.bg) { /* create on the fly */
409 game_theme.bg = gfx_new(game_theme.w, game_theme.h);
410 oldscreen = gfx_screen(game_theme.bg);
411 gfx_clear(0, 0, game_theme.w, game_theme.h);
412 gfx_screen(oldscreen);
413 }
414 d = game_theme.bg;
415 *xoff = game_theme.xoff;
416 *yoff = game_theme.yoff;
417 } else {
418 *xoff = 0;
419 *yoff = 0;
420 d = cache_lookup(gfx_image_cache(), dst);
421 }
422 return d;
423 }
424
425
luaB_sprite_size(lua_State * L)426 static int luaB_sprite_size(lua_State *L) {
427 img_t s = NULL;
428 float v;
429 int w, h;
430 int xoff, yoff;
431 const char *src = luaL_optstring(L, 1, NULL);
432 if (!src)
433 return 0;
434 s = grab_sprite(src, &xoff, &yoff);
435 if (!s)
436 return 0;
437
438 v = game_theme.scale;
439
440 w = ceil ((float)(gfx_img_w(s) - xoff * 2) / v);
441 h = ceil ((float)(gfx_img_h(s) - yoff * 2) / v);
442
443 lua_pushinteger(L, w);
444 lua_pushinteger(L, h);
445 return 2;
446 }
447
448 #define BLIT_COPY 0
449 #define BLIT_DRAW 1
450 #define BLIT_COMPOSE 2
451
luaB_blit_sprite(lua_State * L,int mode)452 static int luaB_blit_sprite(lua_State *L, int mode) {
453 img_t s = NULL, d = NULL;
454 float v;
455 struct lua_pixels *pixels = lua_touserdata(L, 1);
456 const char *src = NULL;
457
458 int x = luaL_optnumber(L, 2, 0);
459 int y = luaL_optnumber(L, 3, 0);
460 int w = luaL_optnumber(L, 4, -1);
461 int h = luaL_optnumber(L, 5, -1);
462 const char *dst = luaL_optstring(L, 6, NULL);
463 int xx = luaL_optnumber(L, 7, 0);
464 int yy = luaL_optnumber(L, 8, 0);
465 int alpha = luaL_optnumber(L, 9, 255);
466 int xoff = 0, yoff = 0;
467 int xoff0 = 0, yoff0 = 0;
468
469 if (!pixels)
470 src = luaL_optstring(L, 1, NULL);
471
472 if ((!src && !pixels) || !dst)
473 return 0;
474
475 if (pixels)
476 s = pixels_img(pixels);
477 if (!s)
478 s = grab_sprite(src, &xoff0, &yoff0);
479
480 d = grab_sprite(dst, &xoff, &yoff);
481
482 if (!s || !d)
483 return 0;
484
485 v = game_theme.scale;
486
487 if (v != 1.0f) {
488 x *= v;
489 y *= v;
490 if (w != -1)
491 w = ceil(w * v);
492 if (h != -1)
493 h = ceil(h * v);
494 xx *= v;
495 yy *= v;
496 }
497
498 if (w == -1)
499 w = gfx_img_w(s) - 2 * xoff0;
500 if (h == -1)
501 h = gfx_img_h(s) - 2 * yoff0;
502
503 game_pict_modify(d);
504
505 game_gfx_clip();
506
507 switch (mode) {
508 case BLIT_DRAW:
509 if (alpha != 255)
510 gfx_draw_from_alpha(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff, alpha);
511 else
512 gfx_draw_from(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff);
513 break;
514 case BLIT_COPY:
515 gfx_copy_from(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff);
516 break;
517 case BLIT_COMPOSE:
518 gfx_compose_from(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff);
519 break;
520 default:
521 break;
522 }
523
524 game_gfx_noclip();
525 lua_pushboolean(L, 1);
526 return 1;
527 }
528
529
luaB_draw_sprite(lua_State * L)530 static int luaB_draw_sprite(lua_State *L)
531 {
532 return luaB_blit_sprite(L, BLIT_DRAW);
533 }
534
luaB_copy_sprite(lua_State * L)535 static int luaB_copy_sprite(lua_State *L)
536 {
537 return luaB_blit_sprite(L, BLIT_COPY);
538 }
539
luaB_compose_sprite(lua_State * L)540 static int luaB_compose_sprite(lua_State *L)
541 {
542 return luaB_blit_sprite(L, BLIT_COMPOSE);
543 }
544
luaB_alpha_sprite(lua_State * L)545 static int luaB_alpha_sprite(lua_State *L) {
546 _spr_t *sp;
547 img_t s;
548 img_t img2 = NULL;
549 const char *key;
550 char sname[sizeof(unsigned long) * 2 + 16];
551
552 const char *src = luaL_optstring(L, 1, NULL);
553 int alpha = luaL_optnumber(L, 2, 255);
554 const char *desc = luaL_optstring(L, 3, NULL);
555
556 if (!src)
557 return 0;
558
559 s = cache_lookup(gfx_image_cache(), src);
560 if (!s)
561 return 0;
562
563 img2 = gfx_alpha_img(s, alpha);
564 if (!img2)
565 return 0;
566
567 if (!desc || sprite_lookup(desc)) {
568 key = sname;
569 sprite_name(src, sname, sizeof(sname));
570 } else
571 key = desc;
572
573 sp = sprite_new(key, img2);
574 if (!sp)
575 goto err;
576 lua_pushstring(L, sname);
577 return 1;
578 err:
579 gfx_free_image(img2);
580 return 0;
581 }
582
luaB_colorkey_sprite(lua_State * L)583 static int luaB_colorkey_sprite(lua_State *L) {
584 img_t s;
585 color_t col;
586
587 const char *src = luaL_optstring(L, 1, NULL);
588 const char *color = luaL_optstring(L, 2, NULL);
589
590 if (color)
591 gfx_parse_color(color, &col);
592
593 if (!src)
594 return 0;
595 s = cache_lookup(gfx_image_cache(), src);
596 if (!s)
597 return 0;
598 if (color)
599 gfx_set_colorkey(s, col);
600 else
601 gfx_unset_colorkey(s);
602 return 0;
603 }
604
luaB_dup_sprite(lua_State * L)605 static int luaB_dup_sprite(lua_State *L) {
606 _spr_t *sp;
607 img_t s;
608 img_t img2 = NULL;
609 const char *key;
610 char sname[sizeof(unsigned long) * 2 + 16];
611 const char *src = luaL_optstring(L, 1, NULL);
612 const char *desc = luaL_optstring(L, 2, NULL);
613
614 if (!src)
615 return 0;
616
617 s = cache_lookup(gfx_image_cache(), src);
618 if (!s)
619 return 0;
620
621 img2 = gfx_dup(s);
622
623 if (!img2)
624 return 0;
625
626 if (!desc || sprite_lookup(desc)) {
627 key = sname;
628 sprite_name(src, sname, sizeof(sname));
629 } else
630 key = desc;
631
632 sp = sprite_new(key, img2);
633 if (!sp)
634 goto err;
635 lua_pushstring(L, sname);
636 return 1;
637 err:
638 gfx_free_image(img2);
639 return 0;
640 }
641
luaB_scale_sprite(lua_State * L)642 static int luaB_scale_sprite(lua_State *L) {
643 _spr_t *sp;
644 img_t s;
645 img_t img2 = NULL;
646 const char *key;
647 char sname[sizeof(unsigned long) * 2 + 16];
648
649 const char *src = luaL_optstring(L, 1, NULL);
650 float xs = luaL_optnumber(L, 2, 0);
651 float ys = luaL_optnumber(L, 3, 0);
652 int smooth = lua_toboolean(L, 4);
653 const char *desc = luaL_optstring(L, 5, NULL);
654
655 if (!src)
656 return 0;
657
658 s = cache_lookup(gfx_image_cache(), src);
659 if (!s)
660 return 0;
661
662 if (xs == 0)
663 xs = 1.0f;
664
665 if (ys == 0)
666 ys = xs;
667
668 img2 = gfx_scale(s, xs, ys, smooth);
669
670 if (!img2)
671 return 0;
672
673 if (!desc || sprite_lookup(desc)) {
674 key = sname;
675 sprite_name(src, sname, sizeof(sname));
676 } else
677 key = desc;
678
679 sp = sprite_new(key, img2);
680 if (!sp)
681 goto err;
682 lua_pushstring(L, sname);
683 return 1;
684 err:
685 gfx_free_image(img2);
686 return 0;
687 }
688
689
luaB_rotate_sprite(lua_State * L)690 static int luaB_rotate_sprite(lua_State *L) {
691 _spr_t *sp;
692 img_t s;
693 img_t img2 = NULL;
694 const char *key;
695 char sname[sizeof(unsigned long) * 2 + 16];
696
697 const char *src = luaL_optstring(L, 1, NULL);
698 float angle = luaL_optnumber(L, 2, 1.0f);
699 int smooth = lua_toboolean(L, 3);
700 const char *desc = luaL_optstring(L, 4, NULL);
701
702 if (!src)
703 return 0;
704
705 s = cache_lookup(gfx_image_cache(), src);
706 if (!s)
707 return 0;
708 img2 = gfx_rotate(s, angle, smooth);
709
710 if (!img2)
711 return 0;
712
713 if (!desc || sprite_lookup(desc)) {
714 key = sname;
715 sprite_name(src, sname, sizeof(sname));
716 } else
717 key = desc;
718
719 sp = sprite_new(key, img2);
720 if (!sp)
721 goto err;
722 lua_pushstring(L, sname);
723 return 1;
724 err:
725 gfx_free_image(img2);
726 return 0;
727 }
728
luaB_fill_sprite(lua_State * L)729 static int luaB_fill_sprite(lua_State *L) {
730 img_t d;
731 float v;
732 const char *dst = luaL_optstring(L, 1, NULL);
733 int x = luaL_optnumber(L, 2, 0);
734 int y = luaL_optnumber(L, 3, 0);
735 int w = luaL_optnumber(L, 4, -1);
736 int h = luaL_optnumber(L, 5, -1);
737 const char *color = luaL_optstring(L, 6, NULL);
738 int xoff = 0, yoff = 0;
739 color_t col = { .r = game_theme.bgcol.r, .g = game_theme.bgcol.g, .b = game_theme.bgcol.b };
740 if (!dst)
741 return 0;
742
743 d = grab_sprite(dst, &xoff, &yoff);
744
745 if (color)
746 gfx_parse_color(color, &col);
747
748 if (!d)
749 return 0;
750
751 v = game_theme.scale;
752
753 if (v != 1.0f) {
754 x *= v;
755 y *= v;
756 if (w != -1)
757 w = ceil(w * v);
758 if (h != -1)
759 h = ceil(h * v);
760 }
761 if (w == -1)
762 w = gfx_img_w(d) - 2 * xoff;
763 if (h == -1)
764 h = gfx_img_h(d) - 2 * yoff;
765 game_pict_modify(d);
766 game_gfx_clip();
767 gfx_img_fill(d, x + xoff, y + yoff, w, h, col);
768 game_gfx_noclip();
769 lua_pushboolean(L, 1);
770 return 1;
771 }
772
luaB_pixel_sprite(lua_State * L)773 static int luaB_pixel_sprite(lua_State *L) {
774 img_t d;
775 float v;
776 int rc, w, h;
777 color_t col = { .r = game_theme.bgcol.r, .g = game_theme.bgcol.g, .b = game_theme.bgcol.b, .a = 255 };
778 const char *dst = luaL_optstring(L, 1, NULL);
779 int x = luaL_optnumber(L, 2, 0);
780 int y = luaL_optnumber(L, 3, 0);
781 const char *color = luaL_optstring(L, 4, NULL);
782 int alpha = luaL_optnumber(L, 5, 255);
783 int xoff = 0, yoff = 0;
784
785 if (!dst)
786 return 0;
787
788 d = grab_sprite(dst, &xoff, &yoff);
789
790 if (color)
791 gfx_parse_color(color, &col);
792
793 if (!d)
794 return 0;
795
796 w = gfx_img_w(d) - 2 * xoff;
797 h = gfx_img_h(d) - 2 * yoff;
798
799 v = game_theme.scale;
800
801 if (v != 1.0f) {
802 x *= v;
803 y *= v;
804 }
805
806 if (color) {
807 if (x < 0 || y < 0 || x >= w || y >= h)
808 return 0;
809 game_pict_modify(d);
810 col.a = alpha;
811 rc = gfx_set_pixel(d, x + xoff, y + yoff, col);
812 } else {
813 rc = gfx_get_pixel(d, x + xoff, y + yoff, &col);
814 }
815
816 if (rc)
817 return 0;
818
819 lua_pushinteger(L, col.r);
820 lua_pushinteger(L, col.g);
821 lua_pushinteger(L, col.b);
822 lua_pushinteger(L, col.a);
823 return 4;
824 }
825
_free_sprite(const char * key)826 static int _free_sprite(const char *key)
827 {
828 _spr_t *sp;
829 if (!key)
830 return -1;
831 sp = sprite_lookup(key);
832
833 if (!sp)
834 return -1;
835
836 cache_forget(gfx_image_cache(), sp->img);
837 cache_shrink(gfx_image_cache());
838
839 list_del(&sp->list);
840 free(sp->name); free(sp);
841 return 0;
842 }
843
luaB_free_sprite(lua_State * L)844 static int luaB_free_sprite(lua_State *L) {
845 const char *key = luaL_optstring(L, 1, NULL);
846 if (_free_sprite(key))
847 return 0;
848 lua_pushboolean(L, 1);
849 return 1;
850 }
851
luaB_free_font(lua_State * L)852 static int luaB_free_font(lua_State *L) {
853 const char *key = luaL_optstring(L, 1, NULL);
854 _fnt_t *fn;
855 if (!key)
856 return 0;
857
858 fn = font_lookup(key);
859 if (!fn)
860 return 0;
861
862 list_del(&fn->list);
863 fnt_free(fn->fnt);
864 free(fn->name); free(fn);
865 lua_pushboolean(L, 1);
866 return 1;
867 }
868
869 extern int theme_setvar(char *name, char *val);
870 extern char *theme_getvar(const char *name);
871
luaB_theme_var(lua_State * L)872 static int luaB_theme_var(lua_State *L) {
873 const char *var = luaL_optstring(L, 1, NULL);
874 const char *val = luaL_optstring(L, 2, NULL);
875 if (var && !val) { /* get */
876 char *p = theme_getvar(var);
877 if (p) {
878 lua_pushstring(L, p);
879 free(p);
880 return 1;
881 }
882 return 0;
883 }
884 if (!val || !var)
885 return 0;
886 /* if (!game_own_theme)
887 return 0; */
888 if (!opt_owntheme)
889 return 0;
890 if (!strcmp(var, "scr.w") ||
891 !strcmp(var, "scr.h") ||
892 !strcmp(var, "scr.scale_aware") ||
893 !strcmp(var, "scr.dpi")) /* filter resolution */
894 return 0;
895 if (!theme_setvar((char*)var, (char*)val)) {
896 if (strcmp(var, "win.scroll.mode")) /* let change scroll mode w/o theme reload */
897 game_theme_changed = 1;
898 }
899 return 0;
900 }
901
luaB_theme_name(lua_State * L)902 static int luaB_theme_name(lua_State *L) {
903 char *name;
904 if (game_own_theme && opt_owntheme) {
905 if (game_own_theme == 2) {
906 name = malloc(strlen(curtheme_dir[THEME_GAME]) + 2);
907 if (!name)
908 return 0;
909 sprintf(name, ".%s", curtheme_dir[THEME_GAME]);
910 lua_pushstring(L, name);
911 free(name);
912 } else {
913 lua_pushstring(L, ".");
914 }
915 } else
916 lua_pushstring(L, curtheme_dir[THEME_GLOBAL]);
917 return 1;
918 }
919
luaB_instead_direct(lua_State * L)920 static int luaB_instead_direct(lua_State *L) {
921 int direct = -1;
922 int old = DIRECT_MODE;
923
924 if (lua_isboolean(L, 1))
925 direct = lua_toboolean(L, 1);
926
927 if (direct == -1) {
928 lua_pushboolean(L, old);
929 return 1;
930 }
931
932 if (!opt_owntheme) {
933 lua_pushboolean(L, 0);
934 return 1;
935 }
936
937 if (direct)
938 game_theme.gfx_mode = GFX_DIRECT_SET(game_theme.gfx_mode);
939 else {
940 if (game_theme.gfx_mode != GFX_MODE_DIRECT) {
941 game_theme.gfx_mode = GFX_DIRECT_CLR(game_theme.gfx_mode);
942 }
943 }
944 lua_pushboolean(L, 1);
945 return 1;
946 }
947 static unsigned long busy_time = 0;
948
instead_ready(void)949 void instead_ready(void)
950 {
951 if (menu_visible() == menu_wait) {
952 menu_toggle(-1);
953 }
954 busy_time = 0;
955 }
956
luaB_stead_busy(lua_State * L)957 static int luaB_stead_busy(lua_State *L) {
958 int busy = lua_toboolean(L, 1);
959 if (busy) {
960 struct inp_event ev;
961 int dirty = 0;
962 memset(&ev, 0, sizeof(ev));
963
964 if (!game_freezed()) {
965 if (game_bg_modify(NULL))
966 game_redraw_all();
967 game_flip();
968 }
969
970 while (input(&ev, 0) == AGAIN);
971 if (ev.type == MOUSE_MOTION) {
972 game_cursor(CURSOR_ON); /* to make all happy */
973 dirty = 1;
974 }
975 if (!busy_time)
976 busy_time = gfx_ticks();
977 if (gfx_ticks() - busy_time >= 750 && menu_visible() != menu_wait) {
978 game_menu(menu_wait);
979 dirty = 1;
980 }
981 if (dirty)
982 game_gfx_commit(0);
983 return 0;
984 }
985 instead_ready();
986 game_gfx_commit(0);
987 return 0;
988 }
989
luaB_mouse_pos(lua_State * L)990 static int luaB_mouse_pos(lua_State *L) {
991 int x = luaL_optnumber(L, 1, -1);
992 int y = luaL_optnumber(L, 2, -1);
993 int m;
994 float v = game_theme.scale;
995 if (x != -1 && y != -1) {
996 x *= v;
997 y *= v;
998 gfx_warp_cursor(x + game_theme.xoff, y + game_theme.yoff);
999 x = -1;
1000 y = -1;
1001 }
1002 m = gfx_cursor(&x, &y);
1003 x = (x - game_theme.xoff) / v;
1004 y = (y - game_theme.yoff) / v;
1005 lua_pushinteger(L, x);
1006 lua_pushinteger(L, y);
1007 lua_pushinteger(L, m);
1008 return 3;
1009 }
1010
luaB_finger_pos(lua_State * L)1011 static int luaB_finger_pos(lua_State *L) {
1012 int x, y;
1013 float pressure;
1014 float v = game_theme.scale;
1015 const char *finger = luaL_optstring(L, 1, NULL);
1016 if (!finger)
1017 return 0;
1018 if (finger_pos(finger, &x, &y, &pressure)) /* no finger */
1019 return 0;
1020 x = (x - game_theme.xoff) / v;
1021 y = (y - game_theme.yoff) / v;
1022 lua_pushinteger(L, x);
1023 lua_pushinteger(L, y);
1024 lua_pushnumber(L, pressure);
1025 return 3;
1026 }
1027
1028 extern int mouse_filter_delay;
1029
luaB_mouse_filter(lua_State * L)1030 static int luaB_mouse_filter(lua_State *L) {
1031 int d = luaL_optnumber(L, 1, -1);
1032 int ov = mouse_filter_delay;
1033 if (d != -1)
1034 mouse_filter_delay = d;
1035 lua_pushinteger(L, ov);
1036 return 1;
1037 }
1038
luaB_mouse_show(lua_State * L)1039 static int luaB_mouse_show(lua_State *L) {
1040 int show = lua_toboolean(L, 1);
1041 int ov = game_cursor_show;
1042 if (lua_isboolean(L, 1))
1043 game_cursor_show = show;
1044 lua_pushboolean(L, ov);
1045 return 1;
1046 }
1047
luaB_get_ticks(lua_State * L)1048 static int luaB_get_ticks(lua_State *L) {
1049 lua_pushinteger(L, gfx_ticks());
1050 return 1;
1051 }
1052
luaB_get_themespath(lua_State * L)1053 static int luaB_get_themespath(lua_State *L) {
1054 char themes_path[PATH_MAX];
1055
1056 if (THEMES_PATH[0] != '/') {
1057 strcpy(themes_path, instead_cwd());
1058 strcat(themes_path, "/");
1059 } else
1060 themes_path[0] = 0;
1061 strcat(themes_path, THEMES_PATH);
1062 unix_path(themes_path);
1063 lua_pushstring(L, themes_path);
1064 return 1;
1065 }
pixels_size(lua_State * L)1066 static int pixels_size(lua_State *L) {
1067 struct lua_pixels *hdr = (struct lua_pixels*)lua_touserdata(L, 1);
1068 if (!hdr || hdr->type != PIXELS_MAGIC)
1069 return 0;
1070 lua_pushinteger(L, hdr->w);
1071 lua_pushinteger(L, hdr->h);
1072 lua_pushnumber(L, hdr->scale);
1073 return 3;
1074 }
1075
1076 #define PXL_BLEND_COPY 1
1077 #define PXL_BLEND_BLEND 2
blend(unsigned char * s,unsigned char * d)1078 static __inline void blend(unsigned char *s, unsigned char *d)
1079 {
1080 unsigned int r, g, b, a;
1081 unsigned int sa = s[3];
1082 unsigned int da = d[3];
1083 a = sa + (da * (255 - sa) >> 8);
1084 r = ((unsigned int)s[0] * sa >> 8) +
1085 ((unsigned int)d[0] * da * (255 - sa) >> 16);
1086 g = ((unsigned int)s[1] * sa >> 8) +
1087 ((unsigned int)d[1] * da * (255 - sa) >> 16);
1088 b = ((unsigned int)s[2] * sa >> 8) +
1089 ((unsigned int)d[2] * da * (255 - sa) >> 16);
1090 d[0] = r; d[1] = g; d[2] = b; d[3] = a;
1091 }
1092
draw(unsigned char * s,unsigned char * d)1093 static __inline void draw(unsigned char *s, unsigned char *d)
1094 {
1095 unsigned int r, g, b, a;
1096 unsigned int sa = s[3];
1097 a = 255;
1098 r = ((unsigned int)s[0] * sa >> 8) +
1099 ((unsigned int)d[0] * (255 - sa) >> 8);
1100 g = ((unsigned int)s[1] * sa >> 8) +
1101 ((unsigned int)d[1] * (255 - sa) >> 8);
1102 b = ((unsigned int)s[2] * sa >> 8) +
1103 ((unsigned int)d[2] * (255 - sa) >> 8);
1104 d[0] = r; d[1] = g; d[2] = b; d[3] = a;
1105 }
pixel(unsigned char * s,unsigned char * d)1106 static __inline void pixel(unsigned char *s, unsigned char *d)
1107 {
1108 unsigned char a_src = s[3];
1109 unsigned char a_dst = d[3];
1110 if (a_src == 255 || a_dst == 0) {
1111 memcpy(d, s, 4);
1112 } else if (a_dst == 255) {
1113 draw(s, d);
1114 } else if (a_src == 0) {
1115 /* nothing to do */
1116 } else {
1117 blend(s, d);
1118 }
1119 }
line0(struct lua_pixels * hdr,int x1,int y1,int dx,int dy,int xd,unsigned char * col)1120 static __inline void line0(struct lua_pixels *hdr, int x1, int y1, int dx, int dy, int xd, unsigned char *col)
1121 {
1122 int dy2 = dy * 2;
1123 int dyx2 = dy2 - dx * 2;
1124 int err = dy2 - dx;
1125 unsigned char *ptr = NULL;
1126 int w = hdr->w; int h = hdr->h;
1127
1128 int ly = w * 4;
1129 int lx = xd * 4;
1130
1131 while ((x1 < 0 || y1 < 0 || x1 >= w) && dx --) {
1132 if (err >= 0) {
1133 y1 ++;
1134 err += dyx2;
1135 } else {
1136 err += dy2;
1137 }
1138 x1 += xd;
1139 }
1140 if (dx < 0)
1141 return;
1142 ptr = (unsigned char*)(hdr + 1);
1143 ptr += (y1 * w + x1) << 2;
1144
1145 pixel(col, ptr);
1146 while (dx --) {
1147 if (err >= 0) {
1148 y1 ++;
1149 if (y1 >= h)
1150 break;
1151 ptr += ly;
1152 err += dyx2;
1153 } else {
1154 err += dy2;
1155 }
1156 x1 += xd;
1157 if (x1 >= w || x1 < 0)
1158 break;
1159 ptr += lx;
1160 pixel(col, ptr);
1161 }
1162 return;
1163 }
1164
line1(struct lua_pixels * hdr,int x1,int y1,int dx,int dy,int xd,unsigned char * col)1165 static __inline void line1(struct lua_pixels *hdr, int x1, int y1, int dx, int dy, int xd, unsigned char *col)
1166 {
1167 int dx2 = dx * 2;
1168 int dxy2 = dx2 - dy * 2;
1169 int err = dx2 - dy;
1170 int w = hdr->w; int h = hdr->h;
1171 unsigned char *ptr = NULL;
1172 int ly = w * 4;
1173 int lx = xd * 4;
1174
1175 while ((x1 < 0 || y1 < 0 || x1 >= w) && dy --) {
1176 if (err >= 0) {
1177 x1 += xd;
1178 err += dxy2;
1179 } else {
1180 err += dx2;
1181 }
1182 y1 ++;
1183 }
1184 if (dy < 0)
1185 return;
1186
1187 ptr = (unsigned char*)(hdr + 1);
1188 ptr += (y1 * w + x1) << 2;
1189
1190 pixel(col, ptr);
1191
1192 while (dy --) {
1193 if (err >= 0) {
1194 x1 += xd;
1195 if (x1 < 0 || x1 >= w)
1196 break;
1197 ptr += lx;
1198 err += dxy2;
1199 } else {
1200 err += dx2;
1201 }
1202 y1 ++;
1203 if (y1 >= h)
1204 break;
1205 ptr += ly;
1206 pixel(col, ptr);
1207 }
1208 return;
1209 }
1210
lineAA(struct lua_pixels * src,int x0,int y0,int x1,int y1,int r,int g,int b,int a)1211 static void lineAA(struct lua_pixels *src, int x0, int y0, int x1, int y1,
1212 int r, int g, int b, int a)
1213 {
1214 int dx, dy, err, e2, sx;
1215 int w, h;
1216 int syp, sxp, ed;
1217 unsigned char *ptr;
1218 unsigned char col[4];
1219 col[0] = r; col[1] = g; col[2] = b; col[3] = a;
1220 if (y0 > y1) {
1221 int tmp;
1222 tmp = x0; x0 = x1; x1 = tmp;
1223 tmp = y0; y0 = y1; y1 = tmp;
1224 }
1225 w = src->w; h = src->h;
1226 if (y1 < 0 || y0 >= h)
1227 return;
1228 if (x0 < x1) {
1229 sx = 1;
1230 if (x0 >= w || x1 < 0)
1231 return;
1232 } else {
1233 sx = -1;
1234 if (x1 >= w || x0 < 0)
1235 return;
1236 }
1237 sxp = sx * 4;
1238 syp = w * 4;
1239
1240 dx = abs(x1 - x0);
1241 dy = y1 - y0;
1242
1243 err = dx - dy;
1244 ed = dx + dy == 0 ? 1: sqrt((float)dx * dx + (float)dy * dy);
1245
1246 while (y0 < 0 || x0 < 0 || x0 >= w) {
1247 e2 = err;
1248 if (2 * e2 >= -dx) {
1249 if (x0 == x1)
1250 break;
1251 err -= dy;
1252 x0 += sx;
1253 }
1254 if (2 * e2 <= dy) {
1255 if (y0 == y1)
1256 break;
1257 err += dx;
1258 y0 ++;
1259 }
1260 }
1261
1262 if (y0 < 0 || x0 < 0 || x0 >= w)
1263 return;
1264
1265 ptr = (unsigned char*)(src + 1);
1266 ptr += (y0 * w + x0) << 2;
1267
1268 while (1) {
1269 unsigned char *optr = ptr;
1270 col[3] = a - a * abs(err - dx + dy) / ed;
1271 pixel(col, ptr);
1272 e2 = err;
1273 if (2 * e2 >= -dx) {
1274 if (x0 == x1)
1275 break;
1276 if (e2 + dy < ed) {
1277 col[3] = a - a * (e2 + dy) / ed;
1278 pixel(col, ptr + syp);
1279 }
1280 err -= dy;
1281 x0 += sx;
1282 if (x0 < 0 || x0 >= w)
1283 break;
1284 ptr += sxp;
1285 }
1286 if (2 * e2 <= dy) {
1287 if (y0 == y1)
1288 break;
1289 if (dx - e2 < ed) {
1290 col[3] = a - a * (dx - e2) / ed;
1291 pixel(col, optr + sxp);
1292 }
1293 err += dx;
1294 y0 ++;
1295 if (y0 >= h)
1296 break;
1297 ptr += syp;
1298 }
1299 }
1300 src->dirty = 1;
1301 }
1302
line(struct lua_pixels * src,int x1,int y1,int x2,int y2,int r,int g,int b,int a)1303 static void line(struct lua_pixels *src, int x1, int y1, int x2, int y2, int r, int g, int b, int a)
1304 {
1305 int dx, dy, tmp;
1306 unsigned char col[4];
1307 if (y1 > y2) {
1308 tmp = y1; y1 = y2; y2 = tmp;
1309 tmp = x1; x1 = x2; x2 = tmp;
1310 }
1311 col[0] = r; col[1] = g; col[2] = b; col[3] = a;
1312 if (y1 >= src->h)
1313 return;
1314 if (y2 < 0)
1315 return;
1316 if (x1 < x2) {
1317 if (x2 < 0)
1318 return;
1319 if (x1 >= src->w)
1320 return;
1321 } else {
1322 if (x1 < 0)
1323 return;
1324 if (x2 >= src->w)
1325 return;
1326 }
1327 dx = x2 - x1;
1328 dy = y2 - y1;
1329 if (dx > 0) {
1330 if (dx > dy) {
1331 line0(src, x1, y1, dx, dy, 1, col);
1332 } else {
1333 line1(src, x1, y1, dx, dy, 1, col);
1334 }
1335 } else {
1336 dx = -dx;
1337 if (dx > dy) {
1338 line0(src, x1, y1, dx, dy, -1, col);
1339 } else {
1340 line1(src, x1, y1, dx, dy, -1, col);
1341 }
1342 }
1343 src->dirty = 1;
1344 }
1345
_pixels_blend(struct lua_pixels * src,int x,int y,int w,int h,struct lua_pixels * dst,int xx,int yy,int mode)1346 static int _pixels_blend(struct lua_pixels *src, int x, int y, int w, int h,
1347 struct lua_pixels *dst, int xx, int yy, int mode)
1348
1349 {
1350 unsigned char *ptr1, *ptr2;
1351 int cy, cx, srcw, dstw;
1352
1353 if (!w)
1354 w = src->w;
1355 if (!h)
1356 h = src->h;
1357
1358 if (x < 0 || x + w > src->w)
1359 return 0;
1360
1361 if (y < 0 || y + h > src->h)
1362 return 0;
1363
1364 if (w <= 0 || h <= 0)
1365 return 0;
1366
1367 if (xx < 0) {
1368 w += xx;
1369 x -= xx;
1370 xx = 0;
1371 }
1372 if (yy < 0) {
1373 h += yy;
1374 y -= yy;
1375 yy = 0;
1376 }
1377 if (w <= 0 || h <= 0)
1378 return 0;
1379
1380 if (xx >= dst->w || yy >= dst->h)
1381 return 0;
1382
1383 if (xx + w > dst->w)
1384 w = dst->w - xx;
1385 if (yy + h > dst->h)
1386 h = dst->h - yy;
1387
1388 ptr1 = (unsigned char *)(src + 1);
1389 ptr2 = (unsigned char *)(dst + 1);
1390 ptr1 += (y * src->w + x) << 2;
1391 ptr2 += (yy * dst->w + xx) << 2;
1392 srcw = src->w * 4; dstw = dst->w * 4;
1393 dst->dirty = 1;
1394 for (cy = 0; cy < h; cy ++) {
1395 if (mode == PXL_BLEND_COPY)
1396 memcpy(ptr2, ptr1, w << 2);
1397 else {
1398 unsigned char *p2 = ptr2;
1399 unsigned char *p1 = ptr1;
1400 for (cx = 0; cx < w; cx ++) {
1401 pixel(p1, p2);
1402 p1 += 4;
1403 p2 += 4;
1404 }
1405 }
1406 ptr2 += dstw;
1407 ptr1 += srcw;
1408 }
1409 return 0;
1410 }
1411
pixels_copy(lua_State * L)1412 static int pixels_copy(lua_State *L) {
1413 int x = 0, y = 0, w = 0, h = 0, xx = 0, yy = 0;
1414 struct lua_pixels *src, *dst;
1415 src = (struct lua_pixels*)lua_touserdata(L, 1);
1416 dst = (struct lua_pixels*)lua_touserdata(L, 2);
1417 if (!dst) {
1418 x = luaL_optnumber(L, 2, 0);
1419 y = luaL_optnumber(L, 3, 0);
1420 w = luaL_optnumber(L, 4, 0);
1421 h = luaL_optnumber(L, 5, 0);
1422 dst = (struct lua_pixels*)lua_touserdata(L, 6);
1423 xx = luaL_optnumber(L, 7, 0);
1424 yy = luaL_optnumber(L, 8, 0);
1425 } else {
1426 xx = luaL_optnumber(L, 3, 0);
1427 yy = luaL_optnumber(L, 4, 0);
1428 }
1429 if (!src || src->type != PIXELS_MAGIC)
1430 return 0;
1431 if (!dst || dst->type != PIXELS_MAGIC)
1432 return 0;
1433 return _pixels_blend(src, x, y, w, h, dst, xx, yy, PXL_BLEND_COPY);
1434 }
1435
pixels_blend(lua_State * L)1436 static int pixels_blend(lua_State *L) {
1437 int x = 0, y = 0, w = 0, h = 0, xx = 0, yy = 0;
1438 struct lua_pixels *src, *dst;
1439 src = (struct lua_pixels*)lua_touserdata(L, 1);
1440 dst = (struct lua_pixels*)lua_touserdata(L, 2);
1441 if (!dst) {
1442 x = luaL_optnumber(L, 2, 0);
1443 y = luaL_optnumber(L, 3, 0);
1444 w = luaL_optnumber(L, 4, 0);
1445 h = luaL_optnumber(L, 5, 0);
1446 dst = (struct lua_pixels*)lua_touserdata(L, 6);
1447 xx = luaL_optnumber(L, 7, 0);
1448 yy = luaL_optnumber(L, 8, 0);
1449 } else {
1450 xx = luaL_optnumber(L, 3, 0);
1451 yy = luaL_optnumber(L, 4, 0);
1452 }
1453 if (!src || src->type != PIXELS_MAGIC)
1454 return 0;
1455 if (!dst || dst->type != PIXELS_MAGIC)
1456 return 0;
1457 return _pixels_blend(src, x, y, w, h, dst, xx, yy, PXL_BLEND_BLEND);
1458 }
1459
_fill(struct lua_pixels * src,int x,int y,int w,int h,int r,int g,int b,int a,int mode)1460 static void _fill(struct lua_pixels *src, int x, int y, int w, int h,
1461 int r, int g, int b, int a, int mode) {
1462 unsigned char col[4];
1463 unsigned char *ptr1;
1464 int cy, cx;
1465 if (!src || src->type != PIXELS_MAGIC)
1466 return;
1467 col[0] = r; col[1] = g; col[2] = b; col[3] = a;
1468 if (!w)
1469 w = src->w;
1470 if (!h)
1471 h = src->h;
1472
1473 if (x < 0) {
1474 w += x;
1475 x = 0;
1476 }
1477 if (y < 0) {
1478 h += y;
1479 y = 0;
1480 }
1481
1482 if (w <= 0 || h <= 0 || x >= src->w || y >= src->h)
1483 return;
1484
1485 if (x + w > src->w)
1486 w = src->w - x;
1487 if (y + h > src->h)
1488 h = src->h - y;
1489
1490 ptr1 = (unsigned char *)(src + 1);
1491 ptr1 += (y * src->w + x) << 2;
1492 src->dirty = 1;
1493 for (cy = 0; cy < h; cy ++) {
1494 unsigned char *p1 = ptr1;
1495 for (cx = 0; cx < w; cx ++) {
1496 if (mode == PXL_BLEND_COPY)
1497 memcpy(p1, col, 4);
1498 else
1499 pixel(col, p1);
1500 p1 += 4;
1501 }
1502 ptr1 += (src->w * 4);
1503 }
1504 return;
1505 }
1506
orient2d(int ax,int ay,int bx,int by,int cx,int cy)1507 static __inline int orient2d(int ax, int ay, int bx, int by, int cx, int cy)
1508 {
1509 return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
1510 }
1511
min3(int a,int b,int c)1512 static __inline int min3(int a, int b, int c)
1513 {
1514 if (a < b) {
1515 if (a < c)
1516 return a;
1517 return c;
1518 } else {
1519 if (b < c)
1520 return b;
1521 return c;
1522 }
1523 }
1524
max3(int a,int b,int c)1525 static __inline int max3(int a, int b, int c)
1526 {
1527 if (a > b) {
1528 if (a > c)
1529 return a;
1530 return c;
1531 } else {
1532 if (b > c)
1533 return b;
1534 return c;
1535 }
1536 }
1537
triangle(struct lua_pixels * src,int x0,int y0,int x1,int y1,int x2,int y2,int r,int g,int b,int a)1538 static void triangle(struct lua_pixels *src, int x0, int y0, int x1, int y1, int x2, int y2, int r, int g, int b, int a)
1539 {
1540 int A01 = y0 - y1, B01 = x1 - x0;
1541 int A12 = y1 - y2, B12 = x2 - x1;
1542 int A20 = y2 - y0, B20 = x0 - x2;
1543
1544 int minx = min3(x0, x1, x2);
1545 int miny = min3(y0, y1, y2);
1546 int maxx = max3(x0, x1, x2);
1547 int maxy = max3(y0, y1, y2);
1548
1549 int w0_row = orient2d(x1, y1, x2, y2, minx, miny);
1550 int w1_row = orient2d(x2, y2, x0, y0, minx, miny);
1551 int w2_row = orient2d(x0, y0, x1, y1, minx, miny);
1552
1553 int y, x, w, h;
1554 int yd;
1555 unsigned char col[4];
1556 unsigned char *ptr;
1557 w = src->w; h = src->h;
1558 yd = 4 * w;
1559 col[0] = r; col[1] = b; col[2] = g; col[3] = a;
1560
1561 if (minx >= w || miny >= h)
1562 return;
1563 if (minx < 0)
1564 minx = 0;
1565 if (miny < 0)
1566 miny = 0;
1567 if (maxy >= h)
1568 maxy = h - 1;
1569 if (maxx >= w)
1570 maxx = w - 1;
1571 ptr = (unsigned char *)(src + 1) + miny * yd + 4 * minx;
1572
1573 src->dirty = 1;
1574
1575 for (y = miny; y <= maxy; y ++) {
1576 int w0 = w0_row;
1577 int w1 = w1_row;
1578 int w2 = w2_row;
1579 unsigned char *p = ptr;
1580 for (x = minx; x <= maxx; x++) {
1581 if ((w0 | w1 | w2) >= 0)
1582 pixel(col, p);
1583 p += 4;
1584 w0 += A12;
1585 w1 += A20;
1586 w2 += A01;
1587 }
1588 w0_row += B12;
1589 w1_row += B20;
1590 w2_row += B01;
1591 ptr += yd;
1592 }
1593 }
fill_circle(struct lua_pixels * src,int xc,int yc,int radius,int r,int g,int b,int a)1594 static void fill_circle(struct lua_pixels *src, int xc, int yc, int radius, int r, int g, int b, int a)
1595 {
1596 int r2 = radius * radius;
1597 int x, y, x1, x2, y1, y2;
1598 unsigned char col[4] = { r, g, b, a };
1599 int w = src->w, h = src->h;
1600 unsigned char *ptr;
1601
1602 if (xc + radius < 0 || yc + radius < 0)
1603 return;
1604 if (xc - radius >= w || yc - radius >= h)
1605 return;
1606
1607 if (radius <= 0)
1608 return;
1609
1610 ptr = (unsigned char *)(src + 1);
1611 src->dirty = 1;
1612 ptr += (w * yc + xc) << 2;
1613
1614 if (radius == 1) {
1615 pixel(col, ptr);
1616 return;
1617 }
1618 y1 = -radius; y2 = radius;
1619 x1 = -radius; x2 = radius;
1620 if (yc - radius < 0)
1621 y1 = -yc;
1622 if (xc - radius < 0)
1623 x1 = -xc;
1624 if (xc + radius >= w)
1625 x2 = w - xc - 1;
1626 if (yc + radius >= h)
1627 y2 = h - yc - 1;
1628 for (y = y1; y <= y2; y ++) {
1629 unsigned char *ptrl = ptr + ((y * w + x1) << 2);
1630 for (x = x1; x <= x2; x++) {
1631 if (x*x + y*y < r2 - 1)
1632 pixel(col, ptrl);
1633 ptrl += 4;
1634 }
1635 }
1636 }
1637
circle(struct lua_pixels * src,int xc,int yc,int rr,int r,int g,int b,int a)1638 static void circle(struct lua_pixels *src, int xc, int yc, int rr, int r, int g, int b, int a)
1639 {
1640 int x = -rr, y = 0, err = 2 - 2 * rr;
1641 unsigned char *ptr = (unsigned char *)(src + 1);
1642 unsigned char col[4] = { r, g, b, a };
1643 int w = src->w, h = src->h;
1644
1645 if (rr <= 0)
1646 return;
1647 if (xc + rr < 0 || yc + rr < 0)
1648 return;
1649 if (xc - rr >= w || yc - rr >= h)
1650 return;
1651 src->dirty = 1;
1652 ptr += (w * yc + xc) * 4;
1653 if (xc - rr >= 0 && xc + rr < w &&
1654 yc - rr >=0 && yc + rr < h) {
1655 do {
1656 int xmy = (x - y * w) * 4;
1657 int yax = (y + x * w) * 4;
1658 pixel(col, ptr - xmy);
1659 pixel(col, ptr - yax);
1660 pixel(col, ptr + xmy);
1661 pixel(col, ptr + yax);
1662
1663 rr = err;
1664 if (rr <= y)
1665 err += ++y * 2 + 1;
1666 if (rr > x || err > y)
1667 err += ++x * 2 + 1;
1668 } while (x < 0);
1669 return;
1670 }
1671 /* slow */
1672 do {
1673 int xmy = (x - y * w) * 4;
1674 int yax = (y + x * w) * 4;
1675 if (((xc - x) | (w - xc + x - 1) |
1676 (yc + y) | (h - yc - y - 1)) >= 0)
1677 pixel(col, ptr - xmy);
1678 if (((xc - y) | (w - xc + y - 1) |
1679 (yc - x) | (h - yc + x - 1)) >= 0)
1680 pixel(col, ptr - yax);
1681 if (((xc + x) | (w - xc - x - 1) |
1682 (yc - y) | (h - yc + y - 1)) >= 0)
1683 pixel(col, ptr + xmy);
1684 if (((xc + y) | (w - xc - y - 1) |
1685 (yc + x) | (h - yc - x - 1)) >= 0)
1686 pixel(col, ptr + yax);
1687 rr = err;
1688 if (rr <= y)
1689 err += ++y * 2 + 1;
1690 if (rr > x || err > y)
1691 err += ++x * 2 + 1;
1692 } while (x < 0);
1693
1694 }
circleAA(struct lua_pixels * src,int xc,int yc,int rr,int r,int g,int b,int a)1695 static void circleAA(struct lua_pixels *src, int xc, int yc, int rr, int r, int g, int b, int a)
1696 {
1697 int p1, p2, p3, p4;
1698 int x = -rr, y = 0, x2, e2, err = 2 - 2 * rr;
1699 unsigned char *ptr = (unsigned char *)(src + 1);
1700 unsigned char col[4] = { r, g, b, a };
1701 int w = src->w, h = src->h;
1702 if (rr <= 0)
1703 return;
1704 if (xc + rr < 0 || yc + rr < 0)
1705 return;
1706 if (xc - rr >= w || yc - rr >= h)
1707 return;
1708 src->dirty = 1;
1709 rr = 1 - err;
1710 ptr += (w * yc + xc) * 4;
1711 do {
1712 int i = 255 * abs(err - 2 *(x + y)-2) / rr;
1713 int xmy = (x - y * w) * 4;
1714 int yax = (y + x * w) * 4;
1715 col[3] = ((255 - i) * a) >> 8;
1716 p1 = 0; p2 = 0; p3 = 0; p4 = 0;
1717 if (((xc - x) | (w - xc + x - 1) |
1718 (yc + y) | (h - yc - y - 1)) >= 0) {
1719 pixel(col, ptr - xmy);
1720 p1 = 1;
1721 }
1722 if (((xc - y) | (w - xc + y - 1) |
1723 (yc - x) | (h - yc + x - 1)) >= 0) {
1724 pixel(col, ptr - yax);
1725 p2 = 1;
1726 }
1727 if (((xc + x) | (w - xc - x - 1) |
1728 (yc - y) | (h - yc + y - 1)) >= 0) {
1729 pixel(col, ptr + xmy);
1730 p3 = 1;
1731 }
1732 if (((xc + y) | (w - xc - y - 1) |
1733 (yc + x) | (h - yc - x - 1)) >= 0) {
1734 pixel(col, ptr + yax);
1735 p4 = 1;
1736 }
1737 e2 = err;
1738 x2 = x;
1739 if (err + y > 0) {
1740 i = 255 * (err - 2 * x - 1) / rr;
1741 if (i < 256) {
1742 col[3] = ((255 - i) * a) >> 8;
1743 if (p1 && yc + y + 1 < h)
1744 pixel(col, ptr - xmy + w * 4);
1745 if (p2 && xc - y - 1 >= 0)
1746 pixel(col, ptr - yax - 4);
1747 if (p3 && yc - y - 1 >= 0)
1748 pixel(col, ptr + xmy - w * 4);
1749 if (p4 && xc + y < w)
1750 pixel(col, ptr + yax + 4);
1751 }
1752 err += ++x * 2 + 1;
1753 }
1754 if (e2 + x <= 0) {
1755 i = 255 * (2 * y + 3 - e2) / rr;
1756 if (i < 256) {
1757 col[3] = ((255 - i) * a) >> 8;
1758 if (p1 && xc - x2 - 1 >= 0)
1759 pixel(col, ptr - xmy - 4);
1760 if (p2 && yc - x2 - 1 >= 0)
1761 pixel(col, ptr - yax - w * 4);
1762 if (p3 && xc + x2 + 1 < w)
1763 pixel(col, ptr + xmy + 4);
1764 if (p4 && yc + x2 + 1 < h)
1765 pixel(col, ptr + yax + w * 4);
1766 }
1767 err += ++y * 2 + 1;
1768 }
1769 } while (x < 0);
1770 }
1771
pixels_fill(lua_State * L)1772 static int pixels_fill(lua_State *L) {
1773 int x = 0, y = 0, w = 0, h = 0, r = 0, g = 0, b = 0, a = 255;
1774 struct lua_pixels *src;
1775 src = (struct lua_pixels*)lua_touserdata(L, 1);
1776 if (!src || src->type != PIXELS_MAGIC)
1777 return 0;
1778 b = luaL_optnumber(L, 8, -1);
1779 if (b < 0) {
1780 r = luaL_optnumber(L, 2, 0);
1781 g = luaL_optnumber(L, 3, 0);
1782 b = luaL_optnumber(L, 4, 0);
1783 a = luaL_optnumber(L, 5, 255);
1784 } else {
1785 x = luaL_optnumber(L, 2, 0);
1786 y = luaL_optnumber(L, 3, 0);
1787 w = luaL_optnumber(L, 4, 0);
1788 h = luaL_optnumber(L, 5, 0);
1789 r = luaL_optnumber(L, 6, 0);
1790 g = luaL_optnumber(L, 7, 0);
1791 b = luaL_optnumber(L, 8, 0);
1792 a = luaL_optnumber(L, 9, 255);
1793 }
1794 _fill(src, x, y, w, h, r, g, b, a, (a == 255)?PXL_BLEND_COPY:PXL_BLEND_BLEND);
1795 return 0;
1796 }
1797
pixels_clear(lua_State * L)1798 static int pixels_clear(lua_State *L) {
1799 int x = 0, y = 0, w = 0, h = 0, r = 0, g = 0, b = 0, a = 0;
1800 struct lua_pixels *src;
1801 src = (struct lua_pixels*)lua_touserdata(L, 1);
1802 if (!src || src->type != PIXELS_MAGIC)
1803 return 0;
1804 b = luaL_optnumber(L, 8, -1);
1805 if (b < 0) {
1806 r = luaL_optnumber(L, 2, 0);
1807 g = luaL_optnumber(L, 3, 0);
1808 b = luaL_optnumber(L, 4, 0);
1809 a = luaL_optnumber(L, 5, 0);
1810 } else {
1811 x = luaL_optnumber(L, 2, 0);
1812 y = luaL_optnumber(L, 3, 0);
1813 w = luaL_optnumber(L, 4, 0);
1814 h = luaL_optnumber(L, 5, 0);
1815 r = luaL_optnumber(L, 6, 0);
1816 g = luaL_optnumber(L, 7, 0);
1817 b = luaL_optnumber(L, 8, 0);
1818 a = luaL_optnumber(L, 9, 0);
1819 }
1820 _fill(src, x, y, w, h, r, g, b, a, PXL_BLEND_COPY);
1821 return 0;
1822 }
1823
1824
pixels_triangle(lua_State * L)1825 static int pixels_triangle(lua_State *L) {
1826 int x0 = 0, y0 = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0, r = 0, g = 0, b = 0, a = 0;
1827 struct lua_pixels *src;
1828 src = (struct lua_pixels*)lua_touserdata(L, 1);
1829 if (!src || src->type != PIXELS_MAGIC)
1830 return 0;
1831 x0 = luaL_optnumber(L, 2, 0);
1832 y0 = luaL_optnumber(L, 3, 0);
1833 x1 = luaL_optnumber(L, 4, 0);
1834 y1 = luaL_optnumber(L, 5, 0);
1835 x2 = luaL_optnumber(L, 6, 0);
1836 y2 = luaL_optnumber(L, 7, 0);
1837 #define XOR_SWAP(x,y) x=x^y; y=x^y; x=x^y;
1838 if (orient2d(x0, y0, x1, y1, x2, y2) < 0) {
1839 XOR_SWAP(x1, x2)
1840 XOR_SWAP(y1, y2)
1841 }
1842 #undef XOR_SWAP
1843 r = luaL_optnumber(L, 8, 0);
1844 g = luaL_optnumber(L, 9, 0);
1845 b = luaL_optnumber(L, 10, 0);
1846 a = luaL_optnumber(L, 11, 255);
1847 triangle(src, x0, y0, x1, y1, x2, y2, r, g, b, a);
1848 return 0;
1849 }
1850
pixels_line(lua_State * L)1851 static int pixels_line(lua_State *L) {
1852 int x1 = 0, y1 = 0, x2 = 0, y2 = 0, r = 0, g = 0, b = 0, a = 255;
1853 struct lua_pixels *src;
1854 src = (struct lua_pixels*)lua_touserdata(L, 1);
1855 if (!src || src->type != PIXELS_MAGIC)
1856 return 0;
1857 x1 = luaL_optnumber(L, 2, 0);
1858 y1 = luaL_optnumber(L, 3, 0);
1859 x2 = luaL_optnumber(L, 4, 0);
1860 y2 = luaL_optnumber(L, 5, 0);
1861 r = luaL_optnumber(L, 6, 0);
1862 g = luaL_optnumber(L, 7, 0);
1863 b = luaL_optnumber(L, 8, 0);
1864 a = luaL_optnumber(L, 9, 255);
1865 line(src, x1, y1, x2, y2, r, g, b, a);
1866 return 0;
1867 }
1868
pixels_lineAA(lua_State * L)1869 static int pixels_lineAA(lua_State *L) {
1870 int x1 = 0, y1 = 0, x2 = 0, y2 = 0, r = 0, g = 0, b = 0, a = 255;
1871 struct lua_pixels *src;
1872 src = (struct lua_pixels*)lua_touserdata(L, 1);
1873 if (!src || src->type != PIXELS_MAGIC)
1874 return 0;
1875 x1 = luaL_optnumber(L, 2, 0);
1876 y1 = luaL_optnumber(L, 3, 0);
1877 x2 = luaL_optnumber(L, 4, 0);
1878 y2 = luaL_optnumber(L, 5, 0);
1879 r = luaL_optnumber(L, 6, 0);
1880 g = luaL_optnumber(L, 7, 0);
1881 b = luaL_optnumber(L, 8, 0);
1882 a = luaL_optnumber(L, 9, 255);
1883 lineAA(src, x1, y1, x2, y2, r, g, b, a);
1884 return 0;
1885 }
pixels_circle(lua_State * L)1886 static int pixels_circle(lua_State *L) {
1887 int xc = 0, yc = 0, rr = 0, r = 0, g = 0, b = 0, a = 255;
1888 struct lua_pixels *src;
1889 src = (struct lua_pixels*)lua_touserdata(L, 1);
1890 if (!src || src->type != PIXELS_MAGIC)
1891 return 0;
1892 xc = luaL_optnumber(L, 2, 0);
1893 yc = luaL_optnumber(L, 3, 0);
1894 rr = luaL_optnumber(L, 4, 0);
1895 r = luaL_optnumber(L, 5, 0);
1896 g = luaL_optnumber(L, 6, 0);
1897 b = luaL_optnumber(L, 7, 0);
1898 a = luaL_optnumber(L, 8, 255);
1899 circle(src, xc, yc, rr, r, g, b, a);
1900 return 0;
1901 }
pixels_circleAA(lua_State * L)1902 static int pixels_circleAA(lua_State *L) {
1903 int xc = 0, yc = 0, rr = 0, r = 0, g = 0, b = 0, a = 255;
1904 struct lua_pixels *src;
1905 src = (struct lua_pixels*)lua_touserdata(L, 1);
1906 if (!src || src->type != PIXELS_MAGIC)
1907 return 0;
1908 xc = luaL_optnumber(L, 2, 0);
1909 yc = luaL_optnumber(L, 3, 0);
1910 rr = luaL_optnumber(L, 4, 0);
1911 r = luaL_optnumber(L, 5, 0);
1912 g = luaL_optnumber(L, 6, 0);
1913 b = luaL_optnumber(L, 7, 0);
1914 a = luaL_optnumber(L, 8, 255);
1915 circleAA(src, xc, yc, rr, r, g, b, a);
1916 return 0;
1917 }
pixels_fill_circle(lua_State * L)1918 static int pixels_fill_circle(lua_State *L) {
1919 int xc = 0, yc = 0, rr = 0, r = 0, g = 0, b = 0, a = 255;
1920 struct lua_pixels *src;
1921 src = (struct lua_pixels*)lua_touserdata(L, 1);
1922 if (!src || src->type != PIXELS_MAGIC)
1923 return 0;
1924 xc = luaL_optnumber(L, 2, 0);
1925 yc = luaL_optnumber(L, 3, 0);
1926 rr = luaL_optnumber(L, 4, 0);
1927 r = luaL_optnumber(L, 5, 0);
1928 g = luaL_optnumber(L, 6, 0);
1929 b = luaL_optnumber(L, 7, 0);
1930 a = luaL_optnumber(L, 8, 255);
1931 fill_circle(src, xc, yc, rr, r, g, b, a);
1932 return 0;
1933 }
1934 struct lua_point {
1935 int x;
1936 int y;
1937 int nodex;
1938 };
1939
1940 /*
1941 http://alienryderflex.com/polygon_fill/
1942 public-domain code by Darel Rex Finley, 2007
1943 */
1944
fill_poly(struct lua_pixels * src,struct lua_point * v,int nr,unsigned char * col)1945 static void fill_poly(struct lua_pixels *src, struct lua_point *v, int nr, unsigned char *col)
1946 {
1947 unsigned char *ptr = (unsigned char *)(src + 1), *ptr1;
1948 int y, x, xmin, xmax, ymin, ymax, swap, w;
1949 int nodes = 0, j, i;
1950 xmin = v[0].x; xmax = v[0].x;
1951 ymin = v[0].y; ymax = v[0].y;
1952
1953 for (i = 0; i < nr; i++) {
1954 if (v[i].x < xmin)
1955 xmin = v[i].x;
1956 if (v[i].x > xmax)
1957 xmax = v[i].x;
1958 if (v[i].y < ymin)
1959 ymin = v[i].y;
1960 if (v[i].y > ymax)
1961 ymax = v[i].y;
1962 }
1963 if (ymin < 0)
1964 ymin = 0;
1965 if (xmin < 0)
1966 xmin = 0;
1967 if (xmax >= src->w)
1968 xmax = src->w;
1969 if (ymax >= src->h)
1970 ymax = src->h;
1971 ptr += (ymin * src->w) << 2;
1972 for (y = ymin; y < ymax; y ++) {
1973 nodes = 0; j = nr - 1;
1974 for (i = 0; i < nr; i++) {
1975 if ((v[i].y < y && v[j].y >= y) ||
1976 (v[j].y < y && v[i].y >= y)) {
1977 v[nodes ++].nodex = v[i].x + ((y - v[i].y) * (v[j].x - v[i].x)) /
1978 (v[j].y - v[i].y);
1979 }
1980 j = i;
1981 }
1982 if (nodes < 2)
1983 goto skip;
1984 i = 0;
1985 while (i < nodes - 1) { /* sort */
1986 if (v[i].nodex > v[i + 1].nodex) {
1987 swap = v[i].nodex;
1988 v[i].nodex = v[i + 1].nodex;
1989 v[i + 1].nodex = swap;
1990 if (i)
1991 i --;
1992 } else {
1993 i ++;
1994 }
1995 }
1996 for (i = 0; i < nodes; i += 2) {
1997 if (v[i].nodex >= xmax)
1998 break;
1999 if (v[i + 1].nodex > xmin) {
2000 if (v[i].nodex < xmin)
2001 v[i].nodex = xmin;
2002 if (v[i + 1].nodex > xmax)
2003 v[i + 1].nodex = xmax;
2004 // hline
2005 src->dirty = 1;
2006 w = (v[i + 1].nodex - v[i].nodex);
2007 ptr1 = ptr + v[i].nodex * 4;
2008 for (x = 0; x < w; x ++) {
2009 pixel(col, ptr1);
2010 ptr1 += 4;
2011 }
2012 }
2013 }
2014 skip:
2015 ptr += src->w * 4;
2016 }
2017 }
2018
pixels_fill_poly(lua_State * L)2019 static int pixels_fill_poly(lua_State *L) {
2020 int nr, i;
2021 struct lua_pixels *src;
2022 struct lua_point *v;
2023 unsigned char col[4];
2024 src = (struct lua_pixels*)lua_touserdata(L, 1);
2025 if (!src || src->type != PIXELS_MAGIC)
2026 return 0;
2027 luaL_checktype(L, 2, LUA_TTABLE);
2028 #if LUA_VERSION_NUM >= 502
2029 nr = lua_rawlen(L, 2);
2030 #else
2031 nr = lua_objlen(L, 2);
2032 #endif
2033 if (nr < 6)
2034 return 0;
2035 col[0] = luaL_optnumber(L, 3, 0);
2036 col[1] = luaL_optnumber(L, 4, 0);
2037 col[2] = luaL_optnumber(L, 5, 0);
2038 col[3] = luaL_optnumber(L, 6, 255);
2039
2040 nr /= 2;
2041 v = malloc(sizeof(*v) * nr);
2042 if (!v)
2043 return 0;
2044 lua_pushvalue(L, 2);
2045 for (i = 0; i < nr; i++) {
2046 lua_pushinteger(L, (i * 2) + 1);
2047 lua_gettable(L, -2);
2048 v[i].x = lua_tonumber(L, -1);
2049 lua_pop(L, 1);
2050 lua_pushinteger(L, (i * 2) + 2);
2051 lua_gettable(L, -2);
2052 v[i].y = lua_tonumber(L, -1);
2053 lua_pop(L, 1);
2054 }
2055 lua_pop(L, 1);
2056 fill_poly(src, v, nr, col);
2057 free(v);
2058 return 0;
2059 }
2060
pixels_value(lua_State * L)2061 static int pixels_value(lua_State *L) {
2062 struct lua_pixels *hdr = (struct lua_pixels*)lua_touserdata(L, 1);
2063 int x = luaL_optnumber(L, 2, -1);
2064 int y = luaL_optnumber(L, 3, -1);
2065 int r = luaL_optnumber(L, 4, -1);
2066 int g = 0, b = 0, a = 0;
2067 unsigned char *ptr;
2068 if (r != -1) {
2069 g = luaL_optnumber(L, 5, 0);
2070 b = luaL_optnumber(L, 6, 0);
2071 a = luaL_optnumber(L, 7, 255);
2072 }
2073 if (x < 0 || y < 0)
2074 return 0;
2075
2076 if (!hdr || hdr->type != PIXELS_MAGIC)
2077 return 0;
2078
2079 if (x >= hdr->w || y >= hdr->h)
2080 return 0;
2081
2082 ptr = (unsigned char*)(hdr + 1);
2083 ptr += ((y * hdr->w + x) << 2);
2084 if (r == -1) {
2085 lua_pushinteger(L, *(ptr ++));
2086 lua_pushinteger(L, *(ptr ++));
2087 lua_pushinteger(L, *(ptr ++));
2088 lua_pushinteger(L, *ptr);
2089 return 4;
2090 }
2091 hdr->dirty = 1;
2092 *(ptr ++) = r;
2093 *(ptr ++) = g;
2094 *(ptr ++) = b;
2095 *(ptr) = a;
2096 return 0;
2097 }
2098
pixels_pixel(lua_State * L)2099 static int pixels_pixel(lua_State *L) {
2100 struct lua_pixels *hdr = (struct lua_pixels*)lua_touserdata(L, 1);
2101 int x = luaL_optnumber(L, 2, -1);
2102 int y = luaL_optnumber(L, 3, -1);
2103 int r = luaL_optnumber(L, 4, -1);
2104 int g, b, a;
2105 unsigned char col[4];
2106 unsigned char *ptr;
2107 if (r == -1)
2108 return 0;
2109
2110 g = luaL_optnumber(L, 5, 0);
2111 b = luaL_optnumber(L, 6, 0);
2112 a = luaL_optnumber(L, 7, 255);
2113
2114 if (x < 0 || y < 0)
2115 return 0;
2116
2117 if (!hdr || hdr->type != PIXELS_MAGIC)
2118 return 0;
2119
2120 if (x >= hdr->w || y >= hdr->h)
2121 return 0;
2122 hdr->dirty = 1;
2123 ptr = (unsigned char*)(hdr + 1);
2124 ptr += ((y * hdr->w + x) << 2);
2125 col[0] = r; col[1] = g; col[2] = b; col[3] = a;
2126 pixel(col, ptr);
2127 return 0;
2128 }
2129
pixels_img(struct lua_pixels * hdr)2130 static img_t pixels_img(struct lua_pixels *hdr) {
2131 int w, h, ww, hh, xx, yy, dx, dy;
2132 unsigned char *ptr, *optr = NULL;
2133 unsigned char *p;
2134 img_t img;
2135 if (!hdr)
2136 return NULL;
2137 if (hdr->type != PIXELS_MAGIC)
2138 return NULL;
2139 img = hdr->img;
2140 if (!img)
2141 return NULL;
2142
2143 if (hdr->direct || !hdr->dirty)
2144 return img;
2145 hdr->dirty = 0;
2146
2147 ptr = (unsigned char*)(hdr + 1);
2148 ww = gfx_img_w(img);
2149 hh = gfx_img_h(img);
2150 w = hdr->w;
2151 h = hdr->h;
2152
2153
2154 p = gfx_get_pixels(img);
2155
2156 if (!p)
2157 return NULL;
2158
2159 dy = 0;
2160
2161 for (yy = 0; yy < hh; yy++) {
2162 unsigned char *ptrl = ptr;
2163
2164 dx = 0;
2165
2166 if (optr) {
2167 memcpy(p, optr, ww * 4);
2168 p += ww * 4;
2169 } else {
2170 optr = p;
2171 for (xx = 0; xx < ww; xx++) {
2172 memcpy(p, ptrl, 4); p += 4;
2173 dx += w;
2174 while (dx >= ww) {
2175 dx -= ww;
2176 ptrl += 4;
2177 }
2178 }
2179 }
2180 dy += h;
2181 while (dy >= hh) {
2182 dy -= hh;
2183 ptr += (w << 2);
2184 optr = NULL;
2185 }
2186 }
2187 gfx_put_pixels(img);
2188 return img;
2189 }
2190
pixels_destroy(lua_State * L)2191 static int pixels_destroy(lua_State *L) {
2192 struct lua_pixels *hdr = (struct lua_pixels*)lua_touserdata(L, 1);
2193 if (!hdr || hdr->type != PIXELS_MAGIC)
2194 return 0;
2195
2196 if (hdr->img)
2197 gfx_free_image(hdr->img);
2198 return 0;
2199 }
2200
pixels_new(lua_State * L,int w,int h,float scale,img_t src)2201 static int pixels_new(lua_State *L, int w, int h, float scale, img_t src) {
2202 int ww, hh, direct = 0;
2203 img_t img2 = NULL, img;
2204 size_t size;
2205 float v = game_theme.scale;
2206 struct lua_pixels *hdr;
2207
2208 if (src) {
2209 w = gfx_img_w(src);
2210 h = gfx_img_h(src);
2211 img2 = gfx_new_rgba(w, h);
2212 if (!img2)
2213 return 0;
2214 gfx_copy_from(src, 0, 0, w, h, img2, 0, 0);
2215 }
2216 if (w <=0 || h <= 0)
2217 return 0;
2218 ww = w; hh = h;
2219 if (v != 1.0f) {
2220 ww = ceil((float)w * v);
2221 hh = ceil((float)h * v);
2222 }
2223 ww = ceil((float)ww * scale);
2224 hh = ceil((float)hh * scale);
2225 size = w * h * 4;
2226 hdr = lua_newuserdata(L, sizeof(*hdr) + size);
2227 if (!hdr) {
2228 if (img2)
2229 gfx_free_image(img2);
2230 return 0;
2231 }
2232
2233 hdr->type = PIXELS_MAGIC;
2234 hdr->img = NULL;
2235 hdr->w = w;
2236 hdr->h = h;
2237 hdr->scale = scale;
2238 hdr->size = size;
2239 hdr->dirty = 0;
2240
2241 if (ww == w && hh == h) { /* direct map */
2242 direct = 1;
2243 img = gfx_new_from(ww, hh, (unsigned char*)(hdr + 1));
2244 } else {
2245 img = gfx_new_rgba(ww, hh);
2246 }
2247 hdr->direct = direct;
2248 if (!img) {
2249 fprintf(stderr, "Error: no free memory\n");
2250 memset(hdr, 0, sizeof(*hdr) + size);
2251 if (img2)
2252 gfx_free_image(img2);
2253 return 1;
2254 }
2255
2256 hdr->img = img;
2257 if (img2) {
2258 unsigned char *ptr = gfx_get_pixels(img2);
2259 if (ptr) {
2260 memcpy(hdr + 1, ptr, size);
2261 gfx_put_pixels(img2);
2262 }
2263 gfx_free_image(img2);
2264 } else {
2265 memset(hdr + 1, 0, size);
2266 }
2267 hdr->dirty = 1;
2268 luaL_getmetatable(L, "pixels metatable");
2269 lua_setmetatable(L, -2);
2270 return 1;
2271
2272 }
luaB_pixels_sprite(lua_State * L)2273 static int luaB_pixels_sprite(lua_State *L) {
2274 const char *fname;
2275 int w, h, rc;
2276 float scale;
2277 img_t img = NULL;
2278
2279 if (!lua_isnumber(L, 1)) {
2280 fname = luaL_optstring(L, 1, NULL);
2281 if (!fname)
2282 return 0;
2283 img = gfx_load_image((char*)fname);
2284 if (!img)
2285 return 0;
2286 // if (!cache_have(gfx_image_cache(), img))
2287 // v = 1.0f; /* do not scale sprites! */
2288 w = 0; h = 0;
2289 scale = luaL_optnumber(L, 2, 1.0f);
2290 } else {
2291 w = luaL_optnumber(L, 1, -1);
2292 h = luaL_optnumber(L, 2, -1);
2293 scale = luaL_optnumber(L, 3, 1.0f);
2294 }
2295 rc = pixels_new(L, w, h, scale, img);
2296 if (img)
2297 gfx_free_image(img);
2298 return rc;
2299 }
2300
pixels_scale(lua_State * L)2301 static int pixels_scale(lua_State *L) {
2302 img_t img, img2;
2303 int rc;
2304 struct lua_pixels *src = (struct lua_pixels*)lua_touserdata(L, 1);
2305 float xs = luaL_optnumber(L, 2, 0);
2306 float ys = luaL_optnumber(L, 3, 0);
2307 int smooth = lua_toboolean(L, 4);
2308
2309 if (!src || src->type != PIXELS_MAGIC)
2310 return 0;
2311 if (ys == 0)
2312 ys = xs;
2313 img = gfx_new_from(src->w, src->h, (unsigned char*)(src + 1));
2314 if (!img)
2315 return 0;
2316 img2 = gfx_scale(img, xs, ys, smooth);
2317 gfx_free_image(img);
2318 rc = pixels_new(L, 0, 0, src->scale, img2);
2319 gfx_free_image(img2);
2320 return rc;
2321 }
2322
pixels_rotate(lua_State * L)2323 static int pixels_rotate(lua_State *L) {
2324 img_t img, img2;
2325 int rc;
2326 struct lua_pixels *src = (struct lua_pixels*)lua_touserdata(L, 1);
2327 float angle = luaL_optnumber(L, 2, 0);
2328 int smooth = lua_toboolean(L, 3);
2329
2330 if (!src || src->type != PIXELS_MAGIC)
2331 return 0;
2332 img = gfx_new_from(src->w, src->h, (unsigned char*)(src + 1));
2333 if (!img)
2334 return 0;
2335 img2 = gfx_rotate(img, angle, smooth);
2336 gfx_free_image(img);
2337 rc = pixels_new(L, 0, 0, src->scale, img2);
2338 gfx_free_image(img2);
2339 return rc;
2340 }
2341
2342 /*
2343 ** Creates pixels metatable.
2344 */
pixels_create_meta(lua_State * L)2345 static int pixels_create_meta (lua_State *L) {
2346 luaL_newmetatable (L, "pixels metatable");
2347 lua_pushstring (L, "__index");
2348 lua_newtable(L);
2349 lua_pushstring (L, "val");
2350 lua_pushcfunction (L, pixels_value);
2351 lua_settable(L, -3);
2352 lua_pushstring (L, "pixel");
2353 lua_pushcfunction (L, pixels_pixel);
2354 lua_settable(L, -3);
2355 lua_pushstring (L, "size");
2356 lua_pushcfunction (L, pixels_size);
2357 lua_settable(L, -3);
2358 lua_pushstring(L, "copy");
2359 lua_pushcfunction (L, pixels_copy);
2360 lua_settable(L, -3);
2361 lua_pushstring(L, "blend");
2362 lua_pushcfunction (L, pixels_blend);
2363 lua_settable(L, -3);
2364 lua_pushstring(L, "clear");
2365 lua_pushcfunction (L, pixels_clear);
2366 lua_settable(L, -3);
2367 lua_pushstring(L, "fill");
2368 lua_pushcfunction (L, pixels_fill);
2369 lua_settable(L, -3);
2370 lua_pushstring(L, "line");
2371 lua_pushcfunction (L, pixels_line);
2372 lua_settable(L, -3);
2373 lua_pushstring(L, "lineAA");
2374 lua_pushcfunction (L, pixels_lineAA);
2375 lua_settable(L, -3);
2376 lua_pushstring(L, "circle");
2377 lua_pushcfunction (L, pixels_circle);
2378 lua_settable(L, -3);
2379 lua_pushstring(L, "circleAA");
2380 lua_pushcfunction (L, pixels_circleAA);
2381 lua_settable(L, -3);
2382 lua_pushstring(L, "fill_circle");
2383 lua_pushcfunction (L, pixels_fill_circle);
2384 lua_settable(L, -3);
2385 lua_pushstring(L, "fill_triangle");
2386 lua_pushcfunction (L, pixels_triangle);
2387 lua_settable(L, -3);
2388 lua_pushstring(L, "fill_poly");
2389 lua_pushcfunction (L, pixels_fill_poly);
2390 lua_settable(L, -3);
2391 lua_pushstring(L, "new_scaled");
2392 lua_pushcfunction (L, pixels_scale);
2393 lua_settable(L, -3);
2394 lua_pushstring(L, "new_rotated");
2395 lua_pushcfunction (L, pixels_rotate);
2396 lua_settable(L, -3);
2397 lua_settable(L, -3);
2398 lua_pushstring (L, "__gc");
2399 lua_pushcfunction (L, pixels_destroy);
2400 lua_settable (L, -3);
2401 return 0;
2402 }
2403
luaB_noise1(lua_State * L)2404 static int luaB_noise1(lua_State *L) {
2405 float r;
2406 int px;
2407 float x = luaL_optnumber(L, 1, 0);
2408 px = luaL_optnumber(L, 2, 0);
2409 if (px > 0) {
2410 r = pnoise1(x, px);
2411 } else {
2412 r = noise1(x);
2413 }
2414 lua_pushnumber(L, r);
2415 return 1;
2416 }
2417
luaB_noise2(lua_State * L)2418 static int luaB_noise2(lua_State *L) {
2419 float r;
2420 int px; int py;
2421 float x = luaL_optnumber(L, 1, 0);
2422 float y = luaL_optnumber(L, 2, 0);
2423 px = luaL_optnumber(L, 3, 0);
2424 py = luaL_optnumber(L, 4, 0);
2425
2426 if (px > 0 && py > 0) {
2427 r = pnoise2(x, y, px, py);
2428 } else {
2429 r = noise2(x, y);
2430 }
2431 lua_pushnumber(L, r);
2432 return 1;
2433 }
2434
luaB_noise3(lua_State * L)2435 static int luaB_noise3(lua_State *L) {
2436 float r;
2437 int px; int py; int pz;
2438 float x = luaL_optnumber(L, 1, 0);
2439 float y = luaL_optnumber(L, 2, 0);
2440 float z = luaL_optnumber(L, 3, 0);
2441 px = luaL_optnumber(L, 4, 0);
2442 py = luaL_optnumber(L, 5, 0);
2443 pz = luaL_optnumber(L, 6, 0);
2444
2445 if (px > 0 && py > 0 && pz > 0) {
2446 r = pnoise3(x, y, z, px, py, pz);
2447 } else {
2448 r = noise3(x, y, z);
2449 }
2450 lua_pushnumber(L, r);
2451 return 1;
2452 }
2453
luaB_noise4(lua_State * L)2454 static int luaB_noise4(lua_State *L) {
2455 float r;
2456 int px; int py; int pz; int pw;
2457 float x = luaL_optnumber(L, 1, 0);
2458 float y = luaL_optnumber(L, 2, 0);
2459 float z = luaL_optnumber(L, 3, 0);
2460 float w = luaL_optnumber(L, 4, 0);
2461 px = luaL_optnumber(L, 5, 0);
2462 py = luaL_optnumber(L, 6, 0);
2463 pz = luaL_optnumber(L, 7, 0);
2464 pw = luaL_optnumber(L, 8, 0);
2465
2466 if (px > 0 && py > 0 && pz > 0 && pw > 0) {
2467 r = pnoise4(x, y, z, w, px, py, pz, pw);
2468 } else {
2469 r = noise4(x, y, z, w);
2470 }
2471 lua_pushnumber(L, r);
2472 return 1;
2473 }
2474
2475 static int callback_ref = 0;
2476 static int render_callback_dirty = 0;
2477
instead_render_callback_dirty(int fl)2478 int instead_render_callback_dirty(int fl)
2479 {
2480 int rc = render_callback_dirty;
2481 if (!callback_ref || game_freezed())
2482 return 0;
2483 if (fl != -1)
2484 render_callback_dirty = fl;
2485 return rc;
2486 }
2487
instead_render_callback(void)2488 void instead_render_callback(void)
2489 {
2490 if (!callback_ref || game_freezed() || render_callback_dirty == -1)
2491 return;
2492
2493 game_cursor(CURSOR_CLEAR);
2494 instead_lock();
2495 lua_rawgeti(instead_lua(), LUA_REGISTRYINDEX, callback_ref);
2496 in_callback ++;
2497 if (instead_pcall(instead_lua(), 0)) { /* on any error */
2498 luaL_unref(instead_lua(), LUA_REGISTRYINDEX, callback_ref);
2499 callback_ref = 0;
2500 }
2501 in_callback --;
2502 instead_clear();
2503 instead_unlock();
2504 if (game_pict_modify(NULL))
2505 render_callback_dirty = -1;
2506 game_cursor(CURSOR_DRAW);
2507 return;
2508 }
2509
luaB_after_callback(lua_State * L)2510 static int luaB_after_callback(lua_State *L) {
2511 if (!opt_owntheme) {
2512 lua_pushboolean(L, 0);
2513 return 1;
2514 }
2515 if (callback_ref)
2516 luaL_unref(L, LUA_REGISTRYINDEX, callback_ref);
2517 callback_ref = 0;
2518 if (lua_isfunction(L, 1))
2519 callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
2520 lua_pushboolean(L, 0);
2521 return 1;
2522 }
2523
luaB_screen_size(lua_State * L)2524 static int luaB_screen_size(lua_State *L) {
2525 int w = 0; int h = 0;
2526 gfx_get_max_mode(&w, &h, MODE_ANY);
2527 lua_pushinteger(L, w);
2528 lua_pushinteger(L, h);
2529 return 2;
2530 }
2531
luaB_screen_dpi(lua_State * L)2532 static int luaB_screen_dpi(lua_State *L) {
2533 lua_pushnumber(L, gfx_get_dpi());
2534 return 1;
2535 }
2536
2537 static const luaL_Reg sprites_funcs[] = {
2538 {"instead_font_load", luaB_load_font},
2539 {"instead_font_free", luaB_free_font},
2540 {"instead_font_scaled_size", luaB_font_size_scaled},
2541 {"instead_sprite_load", luaB_load_sprite},
2542 {"instead_sprite_text", luaB_text_sprite},
2543 {"instead_sprite_free", luaB_free_sprite},
2544 {"instead_sprites_free", luaB_free_sprites},
2545 {"instead_sprite_draw", luaB_draw_sprite},
2546 {"instead_sprite_copy", luaB_copy_sprite},
2547 {"instead_sprite_compose", luaB_compose_sprite},
2548 {"instead_sprite_fill", luaB_fill_sprite},
2549 {"instead_sprite_dup", luaB_dup_sprite},
2550 {"instead_sprite_alpha", luaB_alpha_sprite},
2551 {"instead_sprite_colorkey", luaB_colorkey_sprite},
2552 {"instead_sprite_size", luaB_sprite_size},
2553 {"instead_sprite_scale", luaB_scale_sprite},
2554 {"instead_sprite_rotate", luaB_rotate_sprite},
2555 {"instead_sprite_text_size", luaB_text_size},
2556 {"instead_sprite_pixel", luaB_pixel_sprite},
2557 {"instead_sprite_pixels", luaB_pixels_sprite},
2558 {"instead_theme_var", luaB_theme_var},
2559 {"instead_theme_name", luaB_theme_name},
2560 {"instead_ticks", luaB_get_ticks},
2561 {"instead_busy", luaB_stead_busy},
2562 {"instead_direct", luaB_instead_direct},
2563 {"instead_mouse_pos", luaB_mouse_pos},
2564 {"instead_mouse_filter", luaB_mouse_filter},
2565 {"instead_mouse_show", luaB_mouse_show},
2566 {"instead_finger_pos", luaB_finger_pos},
2567 {"instead_themespath", luaB_get_themespath},
2568 {"instead_noise1", luaB_noise1},
2569 {"instead_noise2", luaB_noise2},
2570 {"instead_noise3", luaB_noise3},
2571 {"instead_noise4", luaB_noise4},
2572 {"instead_screen_size", luaB_screen_size},
2573 {"instead_screen_dpi", luaB_screen_dpi},
2574 {"instead_render_callback", luaB_after_callback},
2575 {NULL, NULL}
2576 };
2577
sprites_done(void)2578 static int sprites_done(void)
2579 {
2580 if (callback_ref) {
2581 luaL_unref(instead_lua(), LUA_REGISTRYINDEX, callback_ref);
2582 callback_ref = 0;
2583 render_callback_dirty = 0;
2584 }
2585 sprites_free();
2586 return 0;
2587 }
2588
sprites_init(void)2589 static int sprites_init(void)
2590 {
2591 char path[PATH_MAX];
2592 if (pixels_create_meta(instead_lua()))
2593 return -1;
2594 instead_api_register(sprites_funcs);
2595 snprintf(path, sizeof(path), "%s/%s", instead_stead_path(), "/ext/sprites.lua");
2596 return instead_loadfile(dirpath(path));
2597 }
2598
sprites_err(void)2599 static int sprites_err(void)
2600 {
2601 if (callback_ref) {
2602 luaL_unref(instead_lua(), LUA_REGISTRYINDEX, callback_ref);
2603 callback_ref = 0;
2604 }
2605 return 0;
2606 }
2607
2608 static struct instead_ext ext = {
2609 .init = sprites_init,
2610 .done = sprites_done,
2611 .err = sprites_err,
2612 };
2613
instead_sprites_init(void)2614 int instead_sprites_init(void)
2615 {
2616 return instead_extension(&ext);
2617 }
2618