1// MIT License
2
3// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#include "core/core.h"
24
25#if defined(TIC_BUILD_WITH_WREN)
26
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
30#include <ctype.h>
31
32#include "tools.h"
33#include "wren.h"
34
35static WrenHandle* game_class = NULL;
36static WrenHandle* new_handle = NULL;
37static WrenHandle* update_handle = NULL;
38static WrenHandle* boot_handle = NULL;
39static WrenHandle* scanline_handle = NULL;
40static WrenHandle* border_handle = NULL;
41static WrenHandle* menu_handle = NULL;
42static WrenHandle* overline_handle = NULL;
43
44static bool loaded = false;
45
46static char const* tic_wren_api = "\n\
47class TIC {\n\
48 foreign static btn()\n\
49 foreign static btn(id)\n\
50 foreign static btnp(id)\n\
51 foreign static btnp(id, hold, period)\n\
52 foreign static key(id)\n\
53 foreign static keyp(id)\n\
54 foreign static keyp(id, hold, period)\n\
55 foreign static mouse()\n\
56 foreign static font(text)\n\
57 foreign static font(text, x, y)\n\
58 foreign static font(text, x, y, alpha_color)\n\
59 foreign static font(text, x, y, alpha_color, w, h)\n\
60 foreign static font(text, x, y, alpha_color, w, h, fixed)\n\
61 foreign static font(text, x, y, alpha_color, w, h, fixed, scale)\n\
62 foreign static spr(id)\n\
63 foreign static spr(id, x, y)\n\
64 foreign static spr(id, x, y, alpha_color)\n\
65 foreign static spr(id, x, y, alpha_color, scale)\n\
66 foreign static spr(id, x, y, alpha_color, scale, flip)\n\
67 foreign static spr(id, x, y, alpha_color, scale, flip, rotate)\n\
68 foreign static spr(id, x, y, alpha_color, scale, flip, rotate, cell_width, cell_height)\n\
69 foreign static map(cell_x, cell_y)\n\
70 foreign static map(cell_x, cell_y, cell_w, cell_h)\n\
71 foreign static map(cell_x, cell_y, cell_w, cell_h, x, y)\n\
72 foreign static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color)\n\
73 foreign static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color, scale)\n\
74 foreign static mset(cell_x, cell_y)\n\
75 foreign static mset(cell_x, cell_y, index)\n\
76 foreign static mget(cell_x, cell_y)\n\
77 foreign static ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3)\n\
78 foreign static ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, src)\n\
79 foreign static ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, src, alpha_color)\n\
80 foreign static ttri_depth()\n\
81 foreign static ttri_depth(z1, z2, z3)\n\
82 foreign static pix(x, y)\n\
83 foreign static pix(x, y, color)\n\
84 foreign static line(x0, y0, x1, y1, color)\n\
85 foreign static circ(x, y, radius, color)\n\
86 foreign static circb(x, y, radius, color)\n\
87 foreign static rect(x, y, w, h, color)\n\
88 foreign static rectb(x, y, w, h, color)\n\
89 foreign static tri(x1, y1, x2, y2, x3, y3, color)\n\
90 foreign static trib(x1, y1, x2, y2, x3, y3, color)\n\
91 foreign static cls()\n\
92 foreign static cls(color)\n\
93 foreign static clip()\n\
94 foreign static clip(x, y, w, h)\n\
95 foreign static peek(addr)\n\
96 foreign static poke(addr, val)\n\
97 foreign static peek(addr, bits)\n\
98 foreign static poke(addr, val, bits)\n\
99 foreign static peek1(addr)\n\
100 foreign static poke1(addr, val)\n\
101 foreign static peek2(addr)\n\
102 foreign static poke2(addr, val)\n\
103 foreign static peek4(addr)\n\
104 foreign static poke4(addr, val)\n\
105 foreign static memcpy(dst, src, size)\n\
106 foreign static memset(dst, src, size)\n\
107 foreign static pmem(index)\n\
108 foreign static pmem(index, val)\n\
109 foreign static sfx(id)\n\
110 foreign static sfx(id, note)\n\
111 foreign static sfx(id, note, duration)\n\
112 foreign static sfx(id, note, duration, channel)\n\
113 foreign static sfx(id, note, duration, channel, volume)\n\
114 foreign static sfx(id, note, duration, channel, volume, speed)\n\
115 foreign static music()\n\
116 foreign static music(track)\n\
117 foreign static music(track, frame)\n\
118 foreign static music(track, frame, loop)\n\
119 foreign static music(track, frame, loop, sustain)\n\
120 foreign static time()\n\
121 foreign static tstamp()\n\
122 foreign static vbank()\n\
123 foreign static vbank(bank)\n\
124 foreign static sync()\n\
125 foreign static sync(mask)\n\
126 foreign static sync(mask, bank)\n\
127 foreign static sync(mask, bank, tocart)\n\
128 foreign static reset()\n\
129 foreign static exit()\n\
130 foreign static map_width__\n\
131 foreign static map_height__\n\
132 foreign static spritesize__\n\
133 foreign static print__(v, x, y, color, fixed, scale, alt)\n\
134 foreign static trace__(msg, color)\n\
135 foreign static spr__(id, x, y, alpha_color, scale, flip, rotate)\n\
136 foreign static fget(index, flag)\n\
137 foreign static fset(index, flag, val)\n\
138 foreign static mgeti__(index)\n\
139 static print(v) { TIC.print__(v.toString, 0, 0, 15, false, 1, false) }\n\
140 static print(v,x,y) { TIC.print__(v.toString, x, y, 15, false, 1, false) }\n\
141 static print(v,x,y,color) { TIC.print__(v.toString, x, y, color, false, 1, false) }\n\
142 static print(v,x,y,color,fixed) { TIC.print__(v.toString, x, y, color, fixed, 1, false) }\n\
143 static print(v,x,y,color,fixed,scale) { TIC.print__(v.toString, x, y, color, fixed, scale, false) }\n\
144 static print(v,x,y,color,fixed,scale,alt) { TIC.print__(v.toString, x, y, color, fixed, scale, alt) }\n\
145 static trace(v) { TIC.trace__(v.toString, 15) }\n\
146 static trace(v,color) { TIC.trace__(v.toString, color) }\n\
147 static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color, scale, remap) {\n\
148 var map_w = TIC.map_width__\n\
149 var map_h = TIC.map_height__\n\
150 var size = TIC.spritesize__ * scale\n\
151 var jj = y\n\
152 var ii = x\n\
153 var flip = 0\n\
154 var rotate = 0\n\
155 for (j in cell_y...cell_y+cell_h) {\n\
156 ii = x\n\
157 for (i in cell_x...cell_x+cell_w) {\n\
158 var mi = i\n\
159 var mj = j\n\
160 while(mi < 0) mi = mi + map_w\n\
161 while(mj < 0) mj = mj + map_h\n\
162 while(mi >= map_w) mi = mi - map_w\n\
163 while(mj >= map_h) mj = mj - map_h\n\
164 var index = mi + mj * map_w\n\
165 var tile_index = TIC.mgeti__(index)\n\
166 var ret = remap.call(tile_index, mi, mj)\n\
167 if (ret.type == List) {\n\
168 tile_index = ret[0]\n\
169 flip = ret[1]\n\
170 rotate = ret[2]\n\
171 } else if (ret.type == Num) {\n\
172 tile_index = ret\n\
173 }\n\
174 TIC.spr__(tile_index, ii, jj, alpha_color, scale, flip, rotate)\n\
175 ii = ii + size\n\
176 }\n\
177 jj = jj + size\n\
178 }\n\
179 }\n\
180 " TIC_FN "(){}\n\
181 " BOOT_FN "(){}\n\
182 " SCN_FN "(row){}\n\
183 " BDR_FN "(row){}\n\
184 " MENU_FN "(index){}\n\
185 " OVR_FN "(){}\n\
186}\n";
187
188static inline void wrenError(WrenVM* vm, const char* msg)
189{
190 wrenEnsureSlots(vm, 1);
191 wrenSetSlotString(vm, 0, msg);
192 wrenAbortFiber(vm, 0);
193}
194
195static inline s32 getWrenNumber(WrenVM* vm, s32 index)
196{
197 return (s32)wrenGetSlotDouble(vm, index);
198}
199
200static inline bool isNumber(WrenVM* vm, s32 index)
201{
202 return wrenGetSlotType(vm, index) == WREN_TYPE_NUM;
203}
204
205static inline bool isString(WrenVM* vm, s32 index)
206{
207 return wrenGetSlotType(vm, index) == WREN_TYPE_STRING;
208}
209
210static inline bool isList(WrenVM* vm, s32 index)
211{
212 return wrenGetSlotType(vm, index) == WREN_TYPE_LIST;
213}
214
215static void closeWren(tic_mem* tic)
216{
217 tic_core* core = (tic_core*)tic;
218 if(core->currentVM)
219 {
220 // release handles
221 if (loaded)
222 {
223 wrenReleaseHandle(core->currentVM, new_handle);
224 wrenReleaseHandle(core->currentVM, update_handle);
225 wrenReleaseHandle(core->currentVM, boot_handle);
226 wrenReleaseHandle(core->currentVM, scanline_handle);
227 wrenReleaseHandle(core->currentVM, border_handle);
228 wrenReleaseHandle(core->currentVM, menu_handle);
229 wrenReleaseHandle(core->currentVM, overline_handle);
230 if (game_class != NULL)
231 {
232 wrenReleaseHandle(core->currentVM, game_class);
233 }
234 }
235
236 wrenFreeVM(core->currentVM);
237 core->currentVM = NULL;
238
239 }
240 loaded = false;
241}
242
243static tic_core* getWrenCore(WrenVM* vm)
244{
245 tic_core* core = wrenGetUserData(vm);
246
247 return core;
248}
249
250static void wren_map_width(WrenVM* vm)
251{
252 wrenSetSlotDouble(vm, 0, TIC_MAP_WIDTH);
253}
254
255static void wren_map_height(WrenVM* vm)
256{
257 wrenSetSlotDouble(vm, 0, TIC_MAP_HEIGHT);
258}
259
260static void wren_mgeti(WrenVM* vm)
261{
262 s32 index = getWrenNumber(vm, 1);
263
264 if(index < 0 || index >= TIC_MAP_WIDTH * TIC_MAP_HEIGHT)
265 {
266 wrenSetSlotDouble(vm, 0, 0);
267 return;
268 }
269
270 tic_mem* tic = (tic_mem*)getWrenCore(vm);
271 wrenSetSlotDouble(vm, 0, *(tic->ram->map.data + index));
272}
273
274static void wren_spritesize(WrenVM* vm)
275{
276 wrenSetSlotDouble(vm, 0, TIC_SPRITESIZE);
277}
278
279static void wren_btn(WrenVM* vm)
280{
281 tic_core* core = getWrenCore(vm);
282 tic_mem* tic = (tic_mem*)core;
283
284 s32 top = wrenGetSlotCount(vm);
285
286 if (top == 1)
287 {
288 wrenSetSlotDouble(vm, 0, tic_api_btn(tic, -1));
289 }
290 else if (top == 2)
291 {
292 bool pressed = tic_api_btn(tic, getWrenNumber(vm, 1) & 0x1f);
293 wrenSetSlotBool(vm, 0, pressed);
294 }
295
296}
297
298static void wren_btnp(WrenVM* vm)
299{
300 tic_core* core = getWrenCore(vm);
301 tic_mem* tic = (tic_mem*)core;
302
303 s32 top = wrenGetSlotCount(vm);
304
305 if (top == 1)
306 {
307 wrenSetSlotBool(vm, 0, tic_api_btnp(tic, -1, -1, -1));
308 }
309 else if(top == 2)
310 {
311 s32 index = getWrenNumber(vm, 1) & 0xf;
312
313 wrenSetSlotBool(vm, 0, tic_api_btnp(tic, index, -1, -1));
314 }
315 else if (top == 4)
316 {
317 s32 index = getWrenNumber(vm, 1) & 0xf;
318 u32 hold = getWrenNumber(vm, 2);
319 u32 period = getWrenNumber(vm, 3);
320
321 wrenSetSlotBool(vm, 0, tic_api_btnp(tic, index, hold, period));
322 }
323}
324
325static void wren_key(WrenVM* vm)
326{
327 tic_core* core = getWrenCore(vm);
328 tic_mem* tic = &core->memory;
329
330 s32 top = wrenGetSlotCount(vm);
331
332 if (top == 1)
333 {
334 wrenSetSlotBool(vm, 0, tic_api_key(tic, tic_key_unknown));
335 }
336 else if (top == 2)
337 {
338 tic_key key = getWrenNumber(vm, 1);
339
340 if(key < tic_keys_count)
341 wrenSetSlotBool(vm, 0, tic_api_key(tic, key));
342 else
343 {
344 wrenError(vm, "unknown keyboard code\n");
345 return;
346 }
347 }
348}
349
350static void wren_keyp(WrenVM* vm)
351{
352 tic_core* core = getWrenCore(vm);
353 tic_mem* tic = &core->memory;
354
355 s32 top = wrenGetSlotCount(vm);
356
357 if (top == 1)
358 {
359 wrenSetSlotBool(vm, 0, tic_api_keyp(tic, tic_key_unknown, -1, -1));
360 }
361 else
362 {
363 tic_key key = getWrenNumber(vm, 1);
364
365 if(key >= tic_keys_count)
366 {
367 wrenError(vm, "unknown keyboard code\n");
368 }
369 else
370 {
371 if(top == 2)
372 {
373 wrenSetSlotBool(vm, 0, tic_api_keyp(tic, key, -1, -1));
374 }
375 else if(top == 4)
376 {
377 u32 hold = getWrenNumber(vm, 2);
378 u32 period = getWrenNumber(vm, 3);
379
380 wrenSetSlotBool(vm, 0, tic_api_keyp(tic, key, hold, period));
381 }
382 }
383 }
384}
385
386
387static void wren_mouse(WrenVM* vm)
388{
389 tic_core* core = getWrenCore(vm);
390
391 const tic80_mouse* mouse = &core->memory.ram->input.mouse;
392
393 wrenEnsureSlots(vm, 6);
394 wrenSetSlotNewList(vm, 0);
395
396 {
397 tic_point pos = tic_api_mouse((tic_mem*)core);
398
399 wrenSetSlotDouble(vm, 1, pos.x);
400 wrenInsertInList(vm, 0, 0, 1);
401
402 wrenSetSlotDouble(vm, 1, pos.y);
403 wrenInsertInList(vm, 0, 1, 1);
404 }
405
406 wrenSetSlotBool(vm, 1, mouse->left ? true : false);
407 wrenInsertInList(vm, 0, 2, 1);
408 wrenSetSlotBool(vm, 1, mouse->middle ? true : false);
409 wrenInsertInList(vm, 0, 3, 1);
410 wrenSetSlotBool(vm, 1, mouse->right ? true : false);
411 wrenInsertInList(vm, 0, 4, 1);
412 wrenSetSlotDouble(vm, 1, mouse->scrollx);
413 wrenInsertInList(vm, 0, 5, 1);
414 wrenSetSlotDouble(vm, 1, mouse->scrolly);
415 wrenInsertInList(vm, 0, 6, 1);
416}
417
418static void wren_print(WrenVM* vm)
419{
420 tic_mem* tic = (tic_mem*)getWrenCore(vm);
421
422 const char* text = wrenGetSlotString(vm, 1);
423
424 s32 x = getWrenNumber(vm, 2);
425 s32 y = getWrenNumber(vm, 3);
426
427 s32 color = getWrenNumber(vm, 4) % TIC_PALETTE_SIZE;
428
429 bool fixed = wrenGetSlotBool(vm, 5);
430
431 s32 scale = getWrenNumber(vm, 6);
432
433 if(scale == 0)
434 {
435 wrenSetSlotDouble(vm, 0, 0);
436 return;
437 }
438
439 bool alt = wrenGetSlotBool(vm, 7);
440
441 s32 size = tic_api_print(tic, text, x, y, color, fixed, scale, alt);
442
443 wrenSetSlotDouble(vm, 0, size);
444}
445
446static void wren_font(WrenVM* vm)
447{
448 tic_mem* tic = (tic_mem*)getWrenCore(vm);
449 s32 top = wrenGetSlotCount(vm);
450
451 if(top > 1)
452 {
453 const char* text = NULL;
454 if (isString(vm, 1))
455 {
456 text = wrenGetSlotString(vm, 1);
457 }
458
459 s32 x = 0;
460 s32 y = 0;
461 s32 width = TIC_SPRITESIZE;
462 s32 height = TIC_SPRITESIZE;
463 u8 chromakey = 0;
464 bool fixed = false;
465 s32 scale = 1;
466 bool alt = false;
467
468 if(top > 3)
469 {
470 x = getWrenNumber(vm, 2);
471 y = getWrenNumber(vm, 3);
472
473 if(top > 4)
474 {
475 chromakey = getWrenNumber(vm, 4);
476
477 if(top > 6)
478 {
479 width = getWrenNumber(vm, 5);
480 height = getWrenNumber(vm, 6);
481
482 if(top > 7)
483 {
484 fixed = wrenGetSlotBool(vm, 7);
485
486 if(top > 8)
487 {
488 scale = getWrenNumber(vm, 8);
489
490 if(top > 9)
491 {
492 alt = wrenGetSlotBool(vm, 9);
493 }
494 }
495 }
496 }
497 }
498 }
499
500 if(scale == 0)
501 {
502 wrenSetSlotDouble(vm, 0, 0);
503 return;
504 }
505
506 s32 size = tic_api_font(tic, text ? text : "null", x, y, &chromakey, 1, width, height, fixed, scale, alt);
507 wrenSetSlotDouble(vm, 0, size);
508 }
509}
510
511static void wren_trace(WrenVM* vm)
512{
513 tic_mem* tic = (tic_mem*)getWrenCore(vm);
514
515 const char* text = wrenGetSlotString(vm, 1);
516 u8 color = (u8)getWrenNumber(vm, 2);
517
518 tic_api_trace(tic, text, color);
519}
520
521static void wren_spr(WrenVM* vm)
522{
523 s32 top = wrenGetSlotCount(vm);
524
525 s32 index = 0;
526 s32 x = 0;
527 s32 y = 0;
528 s32 w = 1;
529 s32 h = 1;
530 s32 scale = 1;
531 tic_flip flip = tic_no_flip;
532 tic_rotate rotate = tic_no_rotate;
533 static u8 colors[TIC_PALETTE_SIZE];
534 s32 count = 0;
535
536 if(top > 1)
537 {
538 index = getWrenNumber(vm, 1);
539
540 if(top > 3)
541 {
542 x = getWrenNumber(vm, 2);
543 y = getWrenNumber(vm, 3);
544
545 if(top > 4)
546 {
547 if(isList(vm, 4))
548 {
549 wrenEnsureSlots(vm, top+1);
550 s32 list_count = wrenGetListCount(vm, 4);
551 for(s32 i = 0; i < TIC_PALETTE_SIZE; i++)
552 {
553 wrenGetListElement(vm, 4, i, top);
554 if(i < list_count && isNumber(vm, top))
555 {
556 colors[i] = getWrenNumber(vm, top);
557 count++;
558 }
559 else
560 {
561 break;
562 }
563 }
564 }
565 else
566 {
567 colors[0] = getWrenNumber(vm, 4);
568 count = 1;
569 }
570
571 if(top > 5)
572 {
573 scale = getWrenNumber(vm, 5);
574
575 if(top > 6)
576 {
577 flip = getWrenNumber(vm, 6);
578
579 if(top > 7)
580 {
581 rotate = getWrenNumber(vm, 7);
582
583 if(top > 9)
584 {
585 w = getWrenNumber(vm, 8);
586 h = getWrenNumber(vm, 9);
587 }
588 }
589 }
590 }
591 }
592 }
593 }
594
595 tic_mem* tic = (tic_mem*)getWrenCore(vm);
596
597 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate);
598}
599
600static void wren_spr_internal(WrenVM* vm)
601{
602 s32 top = wrenGetSlotCount(vm);
603
604 s32 index = getWrenNumber(vm, 1);
605 s32 x = getWrenNumber(vm, 2);
606 s32 y = getWrenNumber(vm, 3);
607
608 static u8 colors[TIC_PALETTE_SIZE];
609 s32 count = 0;
610
611 if(isList(vm, 4))
612 {
613 wrenEnsureSlots(vm, top+1);
614 s32 list_count = wrenGetListCount(vm, 4);
615 for(s32 i = 0; i < TIC_PALETTE_SIZE; i++)
616 {
617 wrenGetListElement(vm, 4, i, top);
618 if(i < list_count && isNumber(vm, top))
619 {
620 colors[i] = getWrenNumber(vm, top);
621 count++;
622 }
623 else
624 {
625 break;
626 }
627 }
628 }
629 else
630 {
631 colors[0] = getWrenNumber(vm, 4);
632 count = 1;
633 }
634
635 s32 scale = getWrenNumber(vm, 5);
636 s32 flip = getWrenNumber(vm, 6);
637 s32 rotate = getWrenNumber(vm, 7);
638
639 tic_mem* tic = (tic_mem*)getWrenCore(vm);
640
641 tic_api_spr(tic, index, x, y, 1, 1, colors, count, scale, flip, rotate);
642}
643
644static void wren_map(WrenVM* vm)
645{
646 s32 x = 0;
647 s32 y = 0;
648 s32 w = TIC_MAP_SCREEN_WIDTH;
649 s32 h = TIC_MAP_SCREEN_HEIGHT;
650 s32 sx = 0;
651 s32 sy = 0;
652 s32 scale = 1;
653 static u8 colors[TIC_PALETTE_SIZE];
654 s32 count = 0;
655
656 s32 top = wrenGetSlotCount(vm);
657
658 if(top > 2)
659 {
660 x = getWrenNumber(vm, 1);
661 y = getWrenNumber(vm, 2);
662
663 if(top > 4)
664 {
665 w = getWrenNumber(vm, 3);
666 h = getWrenNumber(vm, 4);
667
668 if(top > 6)
669 {
670 sx = getWrenNumber(vm, 5);
671 sy = getWrenNumber(vm, 6);
672
673 if(top > 7)
674 {
675 if(isList(vm, 7))
676 {
677 wrenEnsureSlots(vm, top+1);
678 s32 list_count = wrenGetListCount(vm, 7);
679 for(s32 i = 0; i < TIC_PALETTE_SIZE; i++)
680 {
681 wrenGetListElement(vm, 7, i, top);
682 if(i < list_count && isNumber(vm, top))
683 {
684 colors[i] = getWrenNumber(vm, top);
685 count++;
686 }
687 else
688 {
689 break;
690 }
691 }
692 }
693 else
694 {
695 colors[0] = getWrenNumber(vm, 7);
696 count = 1;
697 }
698
699 if(top > 8)
700 {
701 scale = getWrenNumber(vm, 8);
702 }
703 }
704 }
705 }
706 }
707
708 tic_mem* tic = (tic_mem*)getWrenCore(vm);
709
710 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, NULL, NULL);
711}
712
713static void wren_mset(WrenVM* vm)
714{
715 s32 x = getWrenNumber(vm, 1);
716 s32 y = getWrenNumber(vm, 2);
717 u8 value = getWrenNumber(vm, 3);
718
719 tic_mem* tic = (tic_mem*)getWrenCore(vm);
720
721 tic_api_mset(tic, x, y, value);
722}
723
724static void wren_mget(WrenVM* vm)
725{
726 s32 x = getWrenNumber(vm, 1);
727 s32 y = getWrenNumber(vm, 2);
728
729 tic_mem* tic = (tic_mem*)getWrenCore(vm);
730
731 u8 value = tic_api_mget(tic, x, y);
732 wrenSetSlotDouble(vm, 0, value);
733}
734
735static struct
736{
737 float z[3];
738 bool on;
739} depth = {0};
740
741static void wren_ttri_depth(WrenVM* vm)
742{
743 s32 top = wrenGetSlotCount(vm);
744
745 depth.on = false;
746
747 if (top == 4)
748 {
749 for (s32 i = 0; i < COUNT_OF(depth.z); i++)
750 depth.z[i] = (float)wrenGetSlotDouble(vm, i + 1);
751
752 depth.on = true;
753 }
754}
755
756static void wren_ttri(WrenVM* vm)
757{
758 s32 top = wrenGetSlotCount(vm);
759
760 float pt[12];
761
762 for (s32 i = 0; i < COUNT_OF(pt); i++)
763 {
764 pt[i] = (float)wrenGetSlotDouble(vm, i + 1);
765 }
766
767 tic_mem* tic = (tic_mem*)getWrenCore(vm);
768 static u8 colors[TIC_PALETTE_SIZE];
769 s32 count = 0;
770 tic_texture_src src = tic_tiles_texture;
771
772 // check for texture source
773 if (top > 13)
774 {
775 src = getWrenNumber(vm, 13);
776 }
777
778 // check for chroma
779 if(isList(vm, 14))
780 {
781 wrenEnsureSlots(vm, top+1);
782 s32 list_count = wrenGetListCount(vm, 14);
783 for(s32 i = 0; i < TIC_PALETTE_SIZE; i++)
784 {
785 wrenGetListElement(vm, 14, i, top);
786 if(i < list_count && isNumber(vm, top))
787 {
788 colors[i] = getWrenNumber(vm, top);
789 count++;
790 }
791 else
792 {
793 break;
794 }
795 }
796 }
797 else
798 {
799 colors[0] = getWrenNumber(vm, 14);
800 count = 1;
801 }
802
803 tic_api_ttri(tic,
804 pt[0], pt[1], // xy 1
805 pt[2], pt[3], // xy 2
806 pt[4], pt[5], // xy 3
807 pt[6], pt[7], // uv 1
808 pt[8], pt[9], // uv 2
809 pt[10], pt[11], // uv 3
810 src, // texture source
811 colors, count, // chroma
812 depth.z[0], depth.z[1], depth.z[2], depth.on); // depth
813}
814static void wren_pix(WrenVM* vm)
815{
816 s32 top = wrenGetSlotCount(vm);
817
818 s32 x = getWrenNumber(vm, 1);
819 s32 y = getWrenNumber(vm, 2);
820
821 tic_mem* tic = (tic_mem*)getWrenCore(vm);
822
823 if(top > 3)
824 {
825 s32 color = getWrenNumber(vm, 3);
826 tic_api_pix(tic, x, y, color, false);
827 }
828 else
829 {
830 wrenSetSlotDouble(vm, 0, tic_api_pix(tic, x, y, 0, true));
831 }
832}
833
834static void wren_line(WrenVM* vm)
835{
836 float x0 = (float)wrenGetSlotDouble(vm, 1);
837 float y0 = (float)wrenGetSlotDouble(vm, 2);
838 float x1 = (float)wrenGetSlotDouble(vm, 3);
839 float y1 = (float)wrenGetSlotDouble(vm, 4);
840 s32 color = getWrenNumber(vm, 5);
841
842 tic_mem* tic = (tic_mem*)getWrenCore(vm);
843
844 tic_api_line(tic, x0, y0, x1, y1, color);
845}
846
847static void wren_circ(WrenVM* vm)
848{
849 s32 x = getWrenNumber(vm, 1);
850 s32 y = getWrenNumber(vm, 2);
851 s32 radius = getWrenNumber(vm, 3);
852 s32 color = getWrenNumber(vm, 4);
853
854 tic_mem* tic = (tic_mem*)getWrenCore(vm);
855
856 tic_api_circ(tic, x, y, radius, color);
857}
858
859static void wren_circb(WrenVM* vm)
860{
861 s32 x = getWrenNumber(vm, 1);
862 s32 y = getWrenNumber(vm, 2);
863 s32 radius = getWrenNumber(vm, 3);
864 s32 color = getWrenNumber(vm, 4);
865
866 tic_mem* tic = (tic_mem*)getWrenCore(vm);
867
868 tic_api_circb(tic, x, y, radius, color);
869}
870
871static void wren_elli(WrenVM* vm)
872{
873 s32 x = getWrenNumber(vm, 1);
874 s32 y = getWrenNumber(vm, 2);
875 s32 a = getWrenNumber(vm, 3);
876 s32 b = getWrenNumber(vm, 4);
877 s32 color = getWrenNumber(vm, 5);
878
879 tic_mem* tic = (tic_mem*)getWrenCore(vm);
880
881 tic_api_elli(tic, x, y, a, b, color);
882}
883
884static void wren_ellib(WrenVM* vm)
885{
886 s32 x = getWrenNumber(vm, 1);
887 s32 y = getWrenNumber(vm, 2);
888 s32 a = getWrenNumber(vm, 3);
889 s32 b = getWrenNumber(vm, 4);
890 s32 color = getWrenNumber(vm, 5);
891
892 tic_mem* tic = (tic_mem*)getWrenCore(vm);
893
894 tic_api_ellib(tic, x, y, a, b, color);
895}
896
897static void wren_rect(WrenVM* vm)
898{
899 s32 x = getWrenNumber(vm, 1);
900 s32 y = getWrenNumber(vm, 2);
901 s32 w = getWrenNumber(vm, 3);
902 s32 h = getWrenNumber(vm, 4);
903 s32 color = getWrenNumber(vm, 5);
904
905 tic_mem* tic = (tic_mem*)getWrenCore(vm);
906
907 tic_api_rect(tic, x, y, w, h, color);
908}
909
910static void wren_rectb(WrenVM* vm)
911{
912 s32 x = getWrenNumber(vm, 1);
913 s32 y = getWrenNumber(vm, 2);
914 s32 w = getWrenNumber(vm, 3);
915 s32 h = getWrenNumber(vm, 4);
916 s32 color = getWrenNumber(vm, 5);
917
918 tic_mem* tic = (tic_mem*)getWrenCore(vm);
919
920 tic_api_rectb(tic, x, y, w, h, color);
921}
922
923static void wren_tri(WrenVM* vm)
924{
925 float pt[6];
926
927 for(s32 i = 0; i < COUNT_OF(pt); i++)
928 {
929 pt[i] = (float)wrenGetSlotDouble(vm, i + 1);
930 }
931
932 s32 color = getWrenNumber(vm, 7);
933
934 tic_mem* tic = (tic_mem*)getWrenCore(vm);
935
936 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color);
937}
938
939static void wren_trib(WrenVM* vm)
940{
941 float pt[6];
942
943 for(s32 i = 0; i < COUNT_OF(pt); i++)
944 {
945 pt[i] = (float)wrenGetSlotDouble(vm, i + 1);
946 }
947
948 s32 color = getWrenNumber(vm, 7);
949
950 tic_mem* tic = (tic_mem*)getWrenCore(vm);
951
952 tic_api_trib(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color);
953}
954
955static void wren_cls(WrenVM* vm)
956{
957 s32 top = wrenGetSlotCount(vm);
958
959 tic_mem* tic = (tic_mem*)getWrenCore(vm);
960
961 tic_api_cls(tic, top == 1 ? 0 : getWrenNumber(vm, 1));
962}
963
964static void wren_clip(WrenVM* vm)
965{
966 s32 top = wrenGetSlotCount(vm);
967
968 tic_mem* tic = (tic_mem*)getWrenCore(vm);
969
970 if(top == 1)
971 {
972 tic_api_clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT);
973 }
974 else
975 {
976 s32 x = getWrenNumber(vm, 1);
977 s32 y = getWrenNumber(vm, 2);
978 s32 w = getWrenNumber(vm, 3);
979 s32 h = getWrenNumber(vm, 4);
980
981 tic_api_clip(tic, x, y, w, h);
982 }
983}
984
985static void wren_peek(WrenVM* vm)
986{
987 tic_mem* tic = (tic_mem*)getWrenCore(vm);
988
989 s32 address = getWrenNumber(vm, 1);
990 s32 bits = BITS_IN_BYTE;
991
992 if(wrenGetSlotCount(vm) > 2)
993 bits = getWrenNumber(vm, 2);
994
995 wrenSetSlotDouble(vm, 0, tic_api_peek(tic, address, bits));
996}
997
998static void wren_poke(WrenVM* vm)
999{
1000 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1001
1002 s32 address = getWrenNumber(vm, 1);
1003 u8 value = getWrenNumber(vm, 2) & 0xff;
1004 s32 bits = BITS_IN_BYTE;
1005 if(wrenGetSlotCount(vm) > 3)
1006 bits = getWrenNumber(vm, 3);
1007
1008 tic_api_poke(tic, address, value, bits);
1009}
1010
1011static void wren_peek1(WrenVM* vm)
1012{
1013 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1014
1015 s32 address = getWrenNumber(vm, 1);
1016
1017 wrenSetSlotDouble(vm, 0, tic_api_peek1(tic, address));
1018}
1019
1020static void wren_poke1(WrenVM* vm)
1021{
1022 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1023
1024 s32 address = getWrenNumber(vm, 1);
1025 u8 value = getWrenNumber(vm, 2);
1026
1027 tic_api_poke1(tic, address, value);
1028}
1029
1030static void wren_peek2(WrenVM* vm)
1031{
1032 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1033
1034 s32 address = getWrenNumber(vm, 1);
1035
1036 wrenSetSlotDouble(vm, 0, tic_api_peek2(tic, address));
1037}
1038
1039static void wren_poke2(WrenVM* vm)
1040{
1041 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1042
1043 s32 address = getWrenNumber(vm, 1);
1044 u8 value = getWrenNumber(vm, 2);
1045
1046 tic_api_poke2(tic, address, value);
1047}
1048
1049static void wren_peek4(WrenVM* vm)
1050{
1051 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1052
1053 s32 address = getWrenNumber(vm, 1);
1054
1055 wrenSetSlotDouble(vm, 0, tic_api_peek4(tic, address));
1056}
1057
1058static void wren_poke4(WrenVM* vm)
1059{
1060 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1061
1062 s32 address = getWrenNumber(vm, 1);
1063 u8 value = getWrenNumber(vm, 2);
1064
1065 tic_api_poke4(tic, address, value);
1066}
1067
1068static void wren_memcpy(WrenVM* vm)
1069{
1070 s32 dest = getWrenNumber(vm, 1);
1071 s32 src = getWrenNumber(vm, 2);
1072 s32 size = getWrenNumber(vm, 3);
1073
1074 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1075 tic_api_memcpy(tic, dest, src, size);
1076}
1077
1078static void wren_memset(WrenVM* vm)
1079{
1080 s32 dest = getWrenNumber(vm, 1);
1081 u8 value = getWrenNumber(vm, 2);
1082 s32 size = getWrenNumber(vm, 3);
1083
1084 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1085 tic_api_memset(tic, dest, value, size);
1086}
1087
1088static void wren_pmem(WrenVM* vm)
1089{
1090 s32 top = wrenGetSlotCount(vm);
1091 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1092
1093 u32 index = getWrenNumber(vm, 1);
1094
1095 if(index < TIC_PERSISTENT_SIZE)
1096 {
1097 u32 val = tic_api_pmem(tic, index, 0, false);
1098
1099 if(top > 2)
1100 {
1101 tic_api_pmem(tic, index, getWrenNumber(vm, 2), true);
1102 }
1103
1104 wrenSetSlotDouble(vm, 0, val);
1105 }
1106 else wrenError(vm, "invalid persistent tic index\n");
1107}
1108
1109static void wren_sfx(WrenVM* vm)
1110{
1111 s32 top = wrenGetSlotCount(vm);
1112
1113 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1114
1115 s32 index = getWrenNumber(vm, 1);
1116
1117 if(index < SFX_COUNT)
1118 {
1119
1120 s32 note = -1;
1121 s32 octave = -1;
1122 s32 duration = -1;
1123 s32 channel = 0;
1124 s32 volumes[TIC80_SAMPLE_CHANNELS] = {MAX_VOLUME, MAX_VOLUME};
1125 s32 speed = SFX_DEF_SPEED;
1126
1127 if (index >= 0)
1128 {
1129 tic_sample* effect = tic->ram->sfx.samples.data + index;
1130
1131 note = effect->note;
1132 octave = effect->octave;
1133 speed = effect->speed;
1134 }
1135
1136 if(top > 2)
1137 {
1138 if(isNumber(vm, 2))
1139 {
1140 s32 id = getWrenNumber(vm, 2);
1141 note = id % NOTES;
1142 octave = id / NOTES;
1143 }
1144 else if(isString(vm, 2))
1145 {
1146 const char* noteStr = wrenGetSlotString(vm, 2);
1147
1148 if(!tic_tool_parse_note(noteStr, &note, &octave))
1149 {
1150 wrenError(vm, "invalid note, should be like C#4\n");
1151 return;
1152 }
1153 }
1154
1155 if(top > 3)
1156 {
1157 duration = getWrenNumber(vm, 3);
1158
1159 if(top > 4)
1160 {
1161 channel = getWrenNumber(vm, 4);
1162
1163 if(top > 5)
1164 {
1165 if(isList(vm, 5) && wrenGetListCount(vm, 5) == COUNT_OF(volumes))
1166 {
1167 for(s32 i = 0; i < COUNT_OF(volumes); i++)
1168 {
1169 wrenGetListElement(vm, 5, i, top);
1170 if(isNumber(vm, top))
1171 volumes[i] = getWrenNumber(vm, top);
1172 }
1173 }
1174 else volumes[0] = volumes[1] = getWrenNumber(vm, 5);
1175
1176 if(top > 6)
1177 {
1178 speed = getWrenNumber(vm, 6);
1179 }
1180 }
1181 }
1182 }
1183 }
1184
1185 if (channel >= 0 && channel < TIC_SOUND_CHANNELS)
1186 {
1187 tic_api_sfx(tic, index, note, octave, duration, channel, volumes[0] & 0xf, volumes[1] & 0xf, speed);
1188 }
1189 else wrenError(vm, "unknown channel\n");
1190 }
1191 else wrenError(vm, "unknown sfx index\n");
1192}
1193
1194static void wren_music(WrenVM* vm)
1195{
1196 s32 top = wrenGetSlotCount(vm);
1197
1198 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1199
1200 s32 track = -1;
1201 s32 frame = -1;
1202 s32 row = -1;
1203 bool loop = true;
1204 bool sustain = false;
1205 s32 tempo = -1;
1206 s32 speed = -1;
1207
1208 if(top > 1)
1209 {
1210 track = getWrenNumber(vm, 1);
1211
1212 if(track > MUSIC_TRACKS - 1)
1213 {
1214 wrenError(vm, "invalid music track index");
1215 return;
1216 }
1217
1218 if(top > 2)
1219 {
1220 frame = getWrenNumber(vm, 2);
1221
1222 if(top > 3)
1223 {
1224 row = getWrenNumber(vm, 3);
1225
1226 if(top > 4)
1227 {
1228 loop = wrenGetSlotBool(vm, 4);
1229
1230 if(top > 5)
1231 {
1232 sustain = wrenGetSlotBool(vm, 5);
1233
1234 if (top > 6)
1235 {
1236 tempo = getWrenNumber(vm, 6);
1237
1238 if (top > 7)
1239 {
1240 speed = getWrenNumber(vm, 7);
1241 }
1242 }
1243 }
1244 }
1245 }
1246 }
1247 }
1248
1249 tic_api_music(tic, track, frame, row, loop, sustain, tempo, speed);
1250}
1251
1252static void wren_time(WrenVM* vm)
1253{
1254 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1255
1256 wrenSetSlotDouble(vm, 0, tic_api_time(tic));
1257}
1258
1259static void wren_tstamp(WrenVM* vm)
1260{
1261 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1262
1263 wrenSetSlotDouble(vm, 0, tic_api_tstamp(tic));
1264}
1265
1266static void wren_vbank(WrenVM* vm)
1267{
1268 tic_core* core = getWrenCore(vm);
1269 tic_mem* tic = (tic_mem*)core;
1270
1271 s32 prev = core->state.vbank.id;
1272
1273 if(wrenGetSlotCount(vm) == 2)
1274 tic_api_vbank(tic, getWrenNumber(vm, 1));
1275
1276 wrenSetSlotDouble(vm, 0, prev);
1277}
1278
1279static void wren_sync(WrenVM* vm)
1280{
1281 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1282
1283 bool toCart = false;
1284 u32 mask = 0;
1285 s32 bank = 0;
1286
1287 s32 top = wrenGetSlotCount(vm);
1288
1289 if(top > 1)
1290 {
1291 mask = getWrenNumber(vm, 1);
1292
1293 if(top > 2)
1294 {
1295 bank = getWrenNumber(vm, 2);
1296
1297 if(top > 3)
1298 {
1299 toCart = wrenGetSlotBool(vm, 3);
1300 }
1301 }
1302 }
1303
1304 if(bank >= 0 && bank < TIC_BANKS)
1305 tic_api_sync(tic, mask, bank, toCart);
1306 else wrenError(vm, "sync() error, invalid bank");
1307}
1308
1309static void wren_reset(WrenVM* vm)
1310{
1311 tic_core* core = getWrenCore(vm);
1312
1313 core->state.initialized = false;
1314}
1315
1316static void wren_exit(WrenVM* vm)
1317{
1318 tic_api_exit((tic_mem*)getWrenCore(vm));
1319}
1320
1321static void wren_fget(WrenVM* vm)
1322{
1323 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1324
1325 s32 top = wrenGetSlotCount(vm);
1326
1327 if(top > 1)
1328 {
1329 u32 index = getWrenNumber(vm, 1);
1330
1331 if(top > 2)
1332 {
1333 u32 flag = getWrenNumber(vm, 2);
1334 wrenSetSlotBool(vm, 0, tic_api_fget(tic, index, flag));
1335 return;
1336 }
1337 }
1338
1339 wrenError(vm, "invalid params, fget(sprite,flag)\n");
1340}
1341
1342static void wren_fset(WrenVM* vm)
1343{
1344 tic_mem* tic = (tic_mem*)getWrenCore(vm);
1345 s32 top = wrenGetSlotCount(vm);
1346
1347 if(top > 1)
1348 {
1349 u32 index = getWrenNumber(vm, 1);
1350
1351 if(top > 2)
1352 {
1353 u32 flag = getWrenNumber(vm, 2);
1354
1355 if(top > 3)
1356 {
1357 bool value = wrenGetSlotBool(vm, 3);
1358 tic_api_fset(tic, index, flag, value);
1359 return;
1360 }
1361 }
1362 }
1363
1364 wrenError(vm, "invalid params, fset(sprite,flag,value)\n");
1365}
1366
1367static WrenForeignMethodFn foreignTicMethods(const char* signature)
1368{
1369 if (strcmp(signature, "static TIC.btn()" ) == 0) return wren_btn;
1370 if (strcmp(signature, "static TIC.btn(_)" ) == 0) return wren_btn;
1371 if (strcmp(signature, "static TIC.btnp(_)" ) == 0) return wren_btnp;
1372 if (strcmp(signature, "static TIC.btnp(_,_,_)" ) == 0) return wren_btnp;
1373 if (strcmp(signature, "static TIC.key(_)" ) == 0) return wren_key;
1374 if (strcmp(signature, "static TIC.keyp(_)" ) == 0) return wren_keyp;
1375 if (strcmp(signature, "static TIC.keyp(_,_,_)" ) == 0) return wren_keyp;
1376 if (strcmp(signature, "static TIC.mouse()" ) == 0) return wren_mouse;
1377
1378 if (strcmp(signature, "static TIC.font(_)" ) == 0) return wren_font;
1379 if (strcmp(signature, "static TIC.font(_,_,_)" ) == 0) return wren_font;
1380 if (strcmp(signature, "static TIC.font(_,_,_,_)" ) == 0) return wren_font;
1381 if (strcmp(signature, "static TIC.font(_,_,_,_,_,_)" ) == 0) return wren_font;
1382 if (strcmp(signature, "static TIC.font(_,_,_,_,_,_,_)" ) == 0) return wren_font;
1383 if (strcmp(signature, "static TIC.font(_,_,_,_,_,_,_,_)" ) == 0) return wren_font;
1384
1385 if (strcmp(signature, "static TIC.spr(_)" ) == 0) return wren_spr;
1386 if (strcmp(signature, "static TIC.spr(_,_,_)" ) == 0) return wren_spr;
1387 if (strcmp(signature, "static TIC.spr(_,_,_,_)" ) == 0) return wren_spr;
1388 if (strcmp(signature, "static TIC.spr(_,_,_,_,_)" ) == 0) return wren_spr;
1389 if (strcmp(signature, "static TIC.spr(_,_,_,_,_,_)" ) == 0) return wren_spr;
1390 if (strcmp(signature, "static TIC.spr(_,_,_,_,_,_,_)" ) == 0) return wren_spr;
1391 if (strcmp(signature, "static TIC.spr(_,_,_,_,_,_,_,_,_)" ) == 0) return wren_spr;
1392
1393 if (strcmp(signature, "static TIC.map(_,_)" ) == 0) return wren_map;
1394 if (strcmp(signature, "static TIC.map(_,_,_,_)" ) == 0) return wren_map;
1395 if (strcmp(signature, "static TIC.map(_,_,_,_,_,_)" ) == 0) return wren_map;
1396 if (strcmp(signature, "static TIC.map(_,_,_,_,_,_,_)" ) == 0) return wren_map;
1397 if (strcmp(signature, "static TIC.map(_,_,_,_,_,_,_,_)" ) == 0) return wren_map;
1398
1399 if (strcmp(signature, "static TIC.mset(_,_)" ) == 0) return wren_mset;
1400 if (strcmp(signature, "static TIC.mset(_,_,_)" ) == 0) return wren_mset;
1401 if (strcmp(signature, "static TIC.mget(_,_)" ) == 0) return wren_mget;
1402
1403 if (strcmp(signature, "static TIC.ttri(_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_ttri;
1404 if (strcmp(signature, "static TIC.ttri(_,_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_ttri;
1405 if (strcmp(signature, "static TIC.ttri(_,_,_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_ttri;
1406 if (strcmp(signature, "static TIC.ttri_depth()" ) == 0) return wren_ttri_depth;
1407 if (strcmp(signature, "static TIC.ttri_depth(_,_,_)" ) == 0) return wren_ttri_depth;
1408
1409 if (strcmp(signature, "static TIC.pix(_,_)" ) == 0) return wren_pix;
1410 if (strcmp(signature, "static TIC.pix(_,_,_)" ) == 0) return wren_pix;
1411 if (strcmp(signature, "static TIC.line(_,_,_,_,_)" ) == 0) return wren_line;
1412 if (strcmp(signature, "static TIC.circ(_,_,_,_)" ) == 0) return wren_circ;
1413 if (strcmp(signature, "static TIC.circb(_,_,_,_)" ) == 0) return wren_circb;
1414 if (strcmp(signature, "static TIC.rect(_,_,_,_,_)" ) == 0) return wren_rect;
1415 if (strcmp(signature, "static TIC.rectb(_,_,_,_,_)" ) == 0) return wren_rectb;
1416 if (strcmp(signature, "static TIC.tri(_,_,_,_,_,_,_)" ) == 0) return wren_tri;
1417 if (strcmp(signature, "static TIC.trib(_,_,_,_,_,_,_)" ) == 0) return wren_trib;
1418
1419 if (strcmp(signature, "static TIC.cls()" ) == 0) return wren_cls;
1420 if (strcmp(signature, "static TIC.cls(_)" ) == 0) return wren_cls;
1421 if (strcmp(signature, "static TIC.clip()" ) == 0) return wren_clip;
1422 if (strcmp(signature, "static TIC.clip(_,_,_,_)" ) == 0) return wren_clip;
1423
1424 if (strcmp(signature, "static TIC.peek(_)" ) == 0) return wren_peek;
1425 if (strcmp(signature, "static TIC.poke(_,_)" ) == 0) return wren_poke;
1426 if (strcmp(signature, "static TIC.peek(_,_)" ) == 0) return wren_peek;
1427 if (strcmp(signature, "static TIC.poke(_,_,_)" ) == 0) return wren_poke;
1428 if (strcmp(signature, "static TIC.peek1(_)" ) == 0) return wren_peek1;
1429 if (strcmp(signature, "static TIC.poke1(_,_)" ) == 0) return wren_poke1;
1430 if (strcmp(signature, "static TIC.peek2(_)" ) == 0) return wren_peek2;
1431 if (strcmp(signature, "static TIC.poke2(_,_)" ) == 0) return wren_poke2;
1432 if (strcmp(signature, "static TIC.peek4(_)" ) == 0) return wren_peek4;
1433 if (strcmp(signature, "static TIC.poke4(_,_)" ) == 0) return wren_poke4;
1434 if (strcmp(signature, "static TIC.memcpy(_,_,_)" ) == 0) return wren_memcpy;
1435 if (strcmp(signature, "static TIC.memset(_,_,_)" ) == 0) return wren_memset;
1436 if (strcmp(signature, "static TIC.pmem(_)" ) == 0) return wren_pmem;
1437 if (strcmp(signature, "static TIC.pmem(_,_)" ) == 0) return wren_pmem;
1438
1439 if (strcmp(signature, "static TIC.sfx(_)" ) == 0) return wren_sfx;
1440 if (strcmp(signature, "static TIC.sfx(_,_)" ) == 0) return wren_sfx;
1441 if (strcmp(signature, "static TIC.sfx(_,_,_)" ) == 0) return wren_sfx;
1442 if (strcmp(signature, "static TIC.sfx(_,_,_,_)" ) == 0) return wren_sfx;
1443 if (strcmp(signature, "static TIC.sfx(_,_,_,_,_)" ) == 0) return wren_sfx;
1444 if (strcmp(signature, "static TIC.sfx(_,_,_,_,_,_)" ) == 0) return wren_sfx;
1445 if (strcmp(signature, "static TIC.music()" ) == 0) return wren_music;
1446 if (strcmp(signature, "static TIC.music(_)" ) == 0) return wren_music;
1447 if (strcmp(signature, "static TIC.music(_,_)" ) == 0) return wren_music;
1448 if (strcmp(signature, "static TIC.music(_,_,_)" ) == 0) return wren_music;
1449 if (strcmp(signature, "static TIC.music(_,_,_,_)" ) == 0) return wren_music;
1450
1451 if (strcmp(signature, "static TIC.time()" ) == 0) return wren_time;
1452 if (strcmp(signature, "static TIC.tstamp()" ) == 0) return wren_tstamp;
1453 if (strcmp(signature, "static TIC.vbank()" ) == 0) return wren_vbank;
1454 if (strcmp(signature, "static TIC.vbank(_)" ) == 0) return wren_vbank;
1455 if (strcmp(signature, "static TIC.sync()" ) == 0) return wren_sync;
1456 if (strcmp(signature, "static TIC.sync(_)" ) == 0) return wren_sync;
1457 if (strcmp(signature, "static TIC.sync(_,_)" ) == 0) return wren_sync;
1458 if (strcmp(signature, "static TIC.sync(_,_,_)" ) == 0) return wren_sync;
1459 if (strcmp(signature, "static TIC.reset()" ) == 0) return wren_reset;
1460 if (strcmp(signature, "static TIC.exit()" ) == 0) return wren_exit;
1461 if (strcmp(signature, "static TIC.fget(_,_)" ) == 0) return wren_fget;
1462 if (strcmp(signature, "static TIC.fset(_,_,_)" ) == 0) return wren_fset;
1463
1464 // internal functions
1465 if (strcmp(signature, "static TIC.map_width__" ) == 0) return wren_map_width;
1466 if (strcmp(signature, "static TIC.map_height__" ) == 0) return wren_map_height;
1467 if (strcmp(signature, "static TIC.spritesize__" ) == 0) return wren_spritesize;
1468 if (strcmp(signature, "static TIC.print__(_,_,_,_,_,_,_)" ) == 0) return wren_print;
1469 if (strcmp(signature, "static TIC.trace__(_,_)" ) == 0) return wren_trace;
1470 if (strcmp(signature, "static TIC.spr__(_,_,_,_,_,_,_)" ) == 0) return wren_spr_internal;
1471 if (strcmp(signature, "static TIC.mgeti__(_)" ) == 0) return wren_mgeti;
1472
1473 return NULL;
1474}
1475
1476static WrenForeignMethodFn bindForeignMethod(
1477 WrenVM* vm, const char* module, const char* className,
1478 bool isStatic, const char* signature)
1479{
1480 if (strcmp(module, "main") != 0) return NULL;
1481
1482 // For convenience, concatenate all of the method qualifiers into a single signature string.
1483 char fullName[256];
1484 fullName[0] = '\0';
1485 if (isStatic)
1486 {
1487 strcat(fullName, "static ");
1488 }
1489
1490 strcat(fullName, className);
1491 strcat(fullName, ".");
1492 strcat(fullName, signature);
1493
1494 return foreignTicMethods(fullName);
1495}
1496
1497static void initAPI(tic_core* core)
1498{
1499 wrenSetUserData(core->currentVM, core);
1500
1501 if (wrenInterpret(core->currentVM, "main", tic_wren_api) != WREN_RESULT_SUCCESS)
1502 {
1503 core->data->error(core->data->data, "can't load TIC wren api");
1504 }
1505}
1506
1507static void reportError(WrenVM* vm, WrenErrorType type, const char* module, s32 line, const char* message)
1508{
1509 tic_core* core = getWrenCore(vm);
1510
1511 char buffer[1024];
1512
1513 if (module)
1514 {
1515 snprintf(buffer, sizeof buffer, "\"%s\", %d ,\"%s\"",module, line, message);
1516 } else {
1517 snprintf(buffer, sizeof buffer, "%d, \"%s\"",line, message);
1518 }
1519
1520 core->data->error(core->data->data, buffer);
1521}
1522
1523static void writeFn(WrenVM* vm, const char* text)
1524{
1525 tic_core* core = getWrenCore(vm);
1526 u8 color = tic_color_dark_blue;
1527 core->data->trace(core->data->data, text ? text : "null", color);
1528}
1529
1530static bool initWren(tic_mem* tic, const char* code)
1531{
1532 tic_core* core = (tic_core*)tic;
1533 closeWren(tic);
1534
1535 WrenConfiguration config;
1536 wrenInitConfiguration(&config);
1537
1538 config.bindForeignMethodFn = bindForeignMethod;
1539
1540 config.errorFn = reportError;
1541 config.writeFn = writeFn;
1542
1543 WrenVM* vm = core->currentVM = wrenNewVM(&config);
1544
1545 initAPI(core);
1546
1547 if (wrenInterpret(core->currentVM, "main", code) != WREN_RESULT_SUCCESS)
1548 {
1549 return false;
1550 }
1551
1552 loaded = true;
1553
1554 // make handles
1555 wrenEnsureSlots(vm, 1);
1556 wrenGetVariable(vm, "main", "Game", 0);
1557 game_class = wrenGetSlotHandle(vm, 0); // handle from game class
1558
1559 new_handle = wrenMakeCallHandle(vm, "new()");
1560 update_handle = wrenMakeCallHandle(vm, TIC_FN "()");
1561 boot_handle = wrenMakeCallHandle(vm, BOOT_FN "()");
1562 scanline_handle = wrenMakeCallHandle(vm, SCN_FN "(_)");
1563 border_handle = wrenMakeCallHandle(vm, BDR_FN "(_)");
1564 menu_handle = wrenMakeCallHandle(vm, MENU_FN "(_)");
1565 overline_handle = wrenMakeCallHandle(vm, OVR_FN "()");
1566
1567 // create game class
1568 if (game_class)
1569 {
1570 wrenEnsureSlots(vm, 1);
1571 wrenSetSlotHandle(vm, 0, game_class);
1572 wrenCall(vm, new_handle);
1573 wrenReleaseHandle(core->currentVM, game_class); // release game class handle
1574 game_class = NULL;
1575 if (wrenGetSlotCount(vm) == 0)
1576 {
1577 core->data->error(core->data->data, "Error in game class :(");
1578 return false;
1579 }
1580 game_class = wrenGetSlotHandle(vm, 0); // handle from game object
1581 } else {
1582 core->data->error(core->data->data, "'Game class' isn't found :(");
1583 return false;
1584 }
1585
1586 return true;
1587}
1588
1589static void callWrenTick(tic_mem* tic)
1590{
1591 tic_core* core = (tic_core*)tic;
1592 WrenVM* vm = core->currentVM;
1593
1594 if(vm && game_class)
1595 {
1596 wrenEnsureSlots(vm, 1);
1597 wrenSetSlotHandle(vm, 0, game_class);
1598 wrenCall(vm, update_handle);
1599
1600 // call OVR() callback for backward compatibility
1601 if(overline_handle)
1602 {
1603 OVR(core)
1604 {
1605 wrenEnsureSlots(vm, 1);
1606 wrenSetSlotHandle(vm, 0, game_class);
1607 wrenCall(vm, overline_handle);
1608 }
1609 }
1610 }
1611}
1612
1613static void callWrenBoot(tic_mem* tic)
1614{
1615 tic_core* core = (tic_core*)tic;
1616 WrenVM* vm = core->currentVM;
1617
1618 if(vm && game_class)
1619 {
1620 wrenEnsureSlots(vm, 1);
1621 wrenSetSlotHandle(vm, 0, game_class);
1622 wrenCall(vm, boot_handle);
1623 }
1624}
1625
1626static void callWrenIntCallback(tic_mem* tic, s32 value, WrenHandle* handle, void* data)
1627{
1628 tic_core* core = (tic_core*)tic;
1629 WrenVM* vm = core->currentVM;
1630
1631 if(vm && game_class)
1632 {
1633 wrenEnsureSlots(vm, 2);
1634 wrenSetSlotHandle(vm, 0, game_class);
1635 wrenSetSlotDouble(vm, 1, value);
1636 wrenCall(vm, handle);
1637 }
1638}
1639
1640static void callWrenScanline(tic_mem* tic, s32 row, void* data)
1641{
1642 callWrenIntCallback(tic, row, scanline_handle, data);
1643}
1644
1645static void callWrenBorder(tic_mem* tic, s32 row, void* data)
1646{
1647 callWrenIntCallback(tic, row, border_handle, data);
1648}
1649
1650static void callWrenMenu(tic_mem* tic, s32 index, void* data)
1651{
1652 callWrenIntCallback(tic, index, menu_handle, data);
1653}
1654
1655static const char* const WrenKeywords [] =
1656{
1657 "as", "break", "class", "construct", "continue", "else", "false",
1658 "for", "foreign", "if", "import", "in", "is", "null", "return",
1659 "static", "super", "this", "true", "var", "while"
1660};
1661
1662static inline bool isalnum_(char c) {return isalnum(c) || c == '_';}
1663
1664static const tic_outline_item* getWrenOutline(const char* code, s32* size)
1665{
1666 enum{Size = sizeof(tic_outline_item)};
1667
1668 *size = 0;
1669
1670 static tic_outline_item* items = NULL;
1671
1672 if(items)
1673 {
1674 free(items);
1675 items = NULL;
1676 }
1677
1678 const char* ptr = code;
1679
1680 while(true)
1681 {
1682 static const char ClassString[] = "class ";
1683
1684 ptr = strstr(ptr, ClassString);
1685
1686 if(ptr)
1687 {
1688 ptr += sizeof ClassString - 1;
1689
1690 const char* start = ptr;
1691 const char* end = start;
1692
1693 while(*ptr)
1694 {
1695 char c = *ptr;
1696
1697 if(isalnum_(c));
1698 else if(c == ' ' || c == '{')
1699 {
1700 end = ptr;
1701 break;
1702 }
1703 else break;
1704
1705 ptr++;
1706 }
1707
1708 if(end > start)
1709 {
1710 items = realloc(items, (*size + 1) * Size);
1711
1712 items[*size].pos = start;
1713 items[*size].size = (s32)(end - start);
1714
1715 (*size)++;
1716 }
1717 }
1718 else break;
1719 }
1720
1721 return items;
1722}
1723
1724static void evalWren(tic_mem* tic, const char* code)
1725{
1726 tic_core* core = (tic_core*)tic;
1727 wrenInterpret(core->currentVM, "main", code);
1728}
1729
1730tic_script_config WrenSyntaxConfig =
1731{
1732 .id = 16,
1733 .name = "wren",
1734 .fileExtension = ".wren",
1735 .projectComment = "//",
1736 {
1737 .init = initWren,
1738 .close = closeWren,
1739 .tick = callWrenTick,
1740 .boot = callWrenBoot,
1741
1742 .callback =
1743 {
1744 .scanline = callWrenScanline,
1745 .border = callWrenBorder,
1746 .menu = callWrenMenu,
1747 },
1748 },
1749
1750 .getOutline = getWrenOutline,
1751 .eval = evalWren,
1752
1753 .blockCommentStart = "/*",
1754 .blockCommentEnd = "*/",
1755 .blockCommentStart2 = NULL,
1756 .blockCommentEnd2 = NULL,
1757 .blockStringStart = NULL,
1758 .blockStringEnd = NULL,
1759 .singleComment = "//",
1760 .blockEnd = "}",
1761
1762 .keywords = WrenKeywords,
1763 .keywordsCount = COUNT_OF(WrenKeywords),
1764};
1765
1766#endif /* defined(TIC_BUILD_WITH_WREN) */
1767