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#pragma once
24
25#include "retro_endianness.h"
26#include "tic.h"
27#include "time.h"
28
29// convenience macros to loop languages
30#define FOR_EACH_LANG(ln) for (tic_script_config** conf = Languages ; *conf != NULL; conf++ ) { tic_script_config* ln = *conf;
31#define FOR_EACH_LANG_END }
32
33
34typedef struct { u8 index; tic_flip flip; tic_rotate rotate; } RemapResult;
35typedef void(*RemapFunc)(void*, s32 x, s32 y, RemapResult* result);
36
37typedef void(*TraceOutput)(void*, const char*, u8 color);
38typedef void(*ErrorOutput)(void*, const char*);
39typedef void(*ExitCallback)(void*);
40
41typedef struct
42{
43 TraceOutput trace;
44 ErrorOutput error;
45 ExitCallback exit;
46
47 clock_t start;
48
49 void* data;
50} tic_tick_data;
51
52typedef struct tic_mem tic_mem;
53typedef void(*tic_tick)(tic_mem* memory);
54typedef void(*tic_boot)(tic_mem* memory);
55typedef void(*tic_scanline)(tic_mem* memory, s32 row, void* data);
56typedef void(*tic_border)(tic_mem* memory, s32 row, void* data);
57typedef void(*tic_gamemenu)(tic_mem* memory, s32 index, void* data);
58
59typedef struct
60{
61 const char* pos;
62 s32 size;
63} tic_outline_item;
64
65typedef struct
66{
67 tic_scanline scanline;
68 tic_border border;
69 tic_gamemenu menu;
70 void* data;
71} tic_blit_callback;
72
73typedef struct
74{
75 u8 id;
76 const char* name;
77 const char* fileExtension;
78 const char* projectComment;
79 struct
80 {
81 bool(*init)(tic_mem* memory, const char* code);
82 void(*close)(tic_mem* memory);
83
84 tic_tick tick;
85 tic_boot boot;
86 tic_blit_callback callback;
87 };
88
89 const tic_outline_item* (*getOutline)(const char* code, s32* size);
90 void (*eval)(tic_mem* tic, const char* code);
91
92 const char* blockCommentStart;
93 const char* blockCommentEnd;
94 const char* blockCommentStart2;
95 const char* blockCommentEnd2;
96 const char* blockStringStart;
97 const char* blockStringEnd;
98 const char* singleComment;
99 const char* blockEnd;
100
101 const char* const * keywords;
102 s32 keywordsCount;
103} tic_script_config;
104
105extern tic_script_config* Languages[];
106
107typedef enum
108{
109 tic_tiles_texture,
110 tic_map_texture,
111 tic_vbank_texture,
112} tic_texture_src;
113
114typedef struct
115{
116 s32 x, y;
117} tic_point;
118
119typedef struct
120{
121 s32 x, y, w, h;
122} tic_rect;
123
124// SYNC DEFINITION TABLE
125// .--------------------------------- - - -
126// | CART | RAM | INDEX
127// |---------+---------------+------- - - -
128// | | |
129#define TIC_SYNC_LIST(macro) \
130 macro(tiles, tiles, 0) \
131 macro(sprites, sprites, 1) \
132 macro(map, map, 2) \
133 macro(sfx, sfx, 3) \
134 macro(music, music, 4) \
135 macro(palette, vram.palette, 5) \
136 macro(flags, flags, 6) \
137 macro(screen, vram.screen, 7)
138
139enum
140{
141#define TIC_SYNC_DEF(NAME, _, INDEX) tic_sync_##NAME = 1 << INDEX,
142 TIC_SYNC_LIST(TIC_SYNC_DEF)
143#undef TIC_SYNC_DEF
144};
145
146#define TIC_FN "TIC"
147#define BOOT_FN "BOOT"
148#define SCN_FN "SCN"
149#define OVR_FN "OVR" // deprecated since v1.0
150#define BDR_FN "BDR"
151#define MENU_FN "MENU"
152
153#define TIC_CALLBACK_LIST(macro) \
154 macro(TIC, TIC_FN "()", "Main function. It's called at " DEF2STR(TIC80_FRAMERATE) \
155 "fps (" DEF2STR(TIC80_FRAMERATE) " times every second).") \
156 macro(BOOT, BOOT_FN, "Startup function.") \
157 macro(MENU, MENU_FN "(index)", "Game Menu handler.") \
158 macro(SCN, SCN_FN "(row)", "Allows you to execute code between the drawing of each scanline, " \
159 "for example, to manipulate the palette.") \
160 macro(BDR, BDR_FN "(row)", "Allows you to execute code between the drawing of each fullscreen scanline, " \
161 "for example, to manipulate the palette.")
162
163// API DEFINITION TABLE
164// macro
165// (
166// definition
167// help
168// parameters count
169// required parameters count
170// callback?
171// return type
172// function parameters
173// )
174
175#define TIC_API_LIST(macro) \
176 macro(print, \
177 "print(text x=0 y=0 color=15 fixed=false scale=1 smallfont=false) -> width", \
178 \
179 "This will simply print text to the screen using the font defined in config.\n" \
180 "When set to true, the fixed width option ensures that each character " \
181 "will be printed in a `box` of the same size, " \
182 "so the character `i` will occupy the same width as the character `w` for example.\n" \
183 "When fixed width is false, there will be a single space between each character.\n" \
184 "\nTips:\n" \
185 "- To use a custom rastered font, check out `font()`.\n" \
186 "- To print to the console, check out `trace()`.", \
187 7, \
188 1, \
189 0, \
190 s32, \
191 tic_mem*, const char* text, s32 x, s32 y, u8 color, bool fixed, s32 scale, bool alt) \
192 \
193 \
194 macro(cls, \
195 "cls(color=0)", \
196 \
197 "Clear the screen.\n" \
198 "When called this function clear all the screen using the color passed as argument.\n" \
199 "If no parameter is passed first color (0) is used.", \
200 1, \
201 0, \
202 0, \
203 void, \
204 tic_mem*, u8 color) \
205 \
206 \
207 macro(pix, \
208 "pix(x y color)\npix(x y) -> color", \
209 \
210 "This function can read or write pixel color values.\n" \
211 "When called with a color parameter, the pixel at the specified coordinates is set to that color.\n" \
212 "Calling the function without a color parameter returns the color of the pixel at the specified position.", \
213 3, \
214 2, \
215 0, \
216 u8, \
217 tic_mem*, s32 x, s32 y, u8 color, bool get) \
218 \
219 \
220 macro(line, \
221 "line(x0 y0 x1 y1 color)", \
222 \
223 "Draws a straight line from point (x0,y0) to point (x1,y1) in the specified color.", \
224 5, \
225 5, \
226 0, \
227 void, \
228 tic_mem*, float x1, float y1, float x2, float y2, u8 color) \
229 \
230 \
231 macro(rect, \
232 "rect(x y w h color)", \
233 \
234 "This function draws a filled rectangle of the desired size and color at the specified position.\n" \
235 "If you only need to draw the the border or outline of a rectangle (ie not filled) see `rectb()`.", \
236 5, \
237 5, \
238 0, \
239 void, \
240 tic_mem*, s32 x, s32 y, s32 width, s32 height, u8 color) \
241 \
242 \
243 macro(rectb, \
244 "rectb(x y w h color)", \
245 \
246 "This function draws a one pixel thick rectangle border at the position requested.\n" \
247 "If you need to fill the rectangle with a color, see `rect()` instead.", \
248 5, \
249 5, \
250 0, \
251 void, \
252 tic_mem*, s32 x, s32 y, s32 width, s32 height, u8 color) \
253 \
254 \
255 macro(spr, \
256 "spr(id x y colorkey=-1 scale=1 flip=0 rotate=0 w=1 h=1)", \
257 \
258 "Draws the sprite number index at the x and y coordinate.\n" \
259 "You can specify a colorkey in the palette which will be used as the transparent color " \
260 "or use a value of -1 for an opaque sprite.\n" \
261 "The sprite can be scaled up by a desired factor. For example, " \
262 "a scale factor of 2 means an 8x8 pixel sprite is drawn to a 16x16 area of the screen.\n" \
263 "You can flip the sprite where:\n" \
264 "- 0 = No Flip\n" \
265 "- 1 = Flip horizontally\n" \
266 "- 2 = Flip vertically\n" \
267 "- 3 = Flip both vertically and horizontally\n" \
268 "When you rotate the sprite, it's rotated clockwise in 90 steps:\n" \
269 "- 0 = No rotation\n" \
270 "- 1 = 90 rotation\n" \
271 "- 2 = 180 rotation\n" \
272 "- 3 = 270 rotation\n" \
273 "You can draw a composite sprite (consisting of a rectangular region of sprites from the sprite sheet) " \
274 "by specifying the `w` and `h` parameters (which default to 1).", \
275 9, \
276 3, \
277 0, \
278 void, \
279 tic_mem*, s32 index, s32 x, s32 y, s32 w, s32 h, \
280 u8* trans_colors, u8 trans_count, s32 scale, tic_flip flip, tic_rotate rotate) \
281 \
282 \
283 macro(btn, \
284 "btn(id) -> pressed", \
285 \
286 "This function allows you to read the status of one of the buttons attached to TIC.\n" \
287 "The function returns true if the key with the supplied id is currently in the pressed state.\n" \
288 "It remains true for as long as the key is held down.\n" \
289 "If you want to test if a key was just pressed, use `btnp()` instead.", \
290 1, \
291 1, \
292 0, \
293 u32, \
294 tic_mem*, s32 id) \
295 \
296 \
297 macro(btnp, \
298 "btnp(id hold=-1 period=-1) -> pressed", \
299 \
300 "This function allows you to read the status of one of TIC's buttons.\n" \
301 "It returns true only if the key has been pressed since the last frame.\n" \
302 "You can also use the optional hold and period parameters " \
303 "which allow you to check if a button is being held down.\n" \
304 "After the time specified by hold has elapsed, " \
305 "btnp will return true each time period is passed if the key is still down.\n" \
306 "For example, to re-examine the state of button `0` after 2 seconds " \
307 "and continue to check its state every 1/10th of a second, you would use btnp(0, 120, 6).\n" \
308 "Since time is expressed in ticks and TIC runs at 60 frames per second, " \
309 "we use the value of 120 to wait 2 seconds and 6 ticks (ie 60/10) as the interval for re-checking.", \
310 3, \
311 1, \
312 0, \
313 u32, \
314 tic_mem*, s32 id, s32 hold, s32 period) \
315 \
316 \
317 macro(sfx, \
318 "sfx(id note=-1 duration=-1 channel=0 volume=15 speed=0)", \
319 \
320 "This function will play the sound with `id` created in the sfx editor.\n" \
321 "Calling the function with id set to -1 will stop playing the channel.\n" \
322 "The note can be supplied as an integer between 0 and 95 (representing 8 octaves of 12 notes each) " \
323 "or as a string giving the note name and octave.\n" \
324 "For example, a note value of `14` will play the note `D` in the second octave.\n" \
325 "The same note could be specified by the string `D-2`.\n" \
326 "Note names consist of two characters, " \
327 "the note itself (in upper case) followed by `-` to represent the natural note or `#` to represent a sharp.\n" \
328 "There is no option to indicate flat values.\n" \
329 "The available note names are therefore: C-, C#, D-, D#, E-, F-, F#, G-, G#, A-, A#, B-.\n" \
330 "The `octave` is specified using a single digit in the range 0 to 8.\n" \
331 "The `duration` specifies how many ticks to play the sound for since TIC-80 runs at 60 frames per second, " \
332 "a value of 30 represents half a second.\n" \
333 "A value of -1 will play the sound continuously.\n" \
334 "The `channel` parameter indicates which of the four channels to use. Allowed values are 0 to 3.\n" \
335 "The `volume` can be between 0 and 15.\n" \
336 "The `speed` in the range -4 to 3 can be specified and means how many `ticks+1` to play each step, " \
337 "so speed==0 means 1 tick per step.", \
338 6, \
339 1, \
340 0, \
341 void, \
342 tic_mem*, s32 index, s32 note, s32 octave, \
343 s32 duration, s32 channel, s32 left, s32 right, s32 speed) \
344 \
345 \
346 macro(map, \
347 "map(x=0 y=0 w=30 h=17 sx=0 sy=0 colorkey=-1 scale=1 remap=nil)", \
348 \
349 "The map consists of cells of 8x8 pixels, each of which can be filled with a sprite using the map editor.\n" \
350 "The map can be up to 240 cells wide by 136 deep.\n" \
351 "This function will draw the desired area of the map to a specified screen position.\n" \
352 "For example, map(5,5,12,10,0,0) will draw a 12x10 section of the map, " \
353 "starting from map co-ordinates (5,5) to screen position (0,0).\n" \
354 "The map function's last parameter is a powerful callback function " \
355 "for changing how map cells (sprites) are drawn when map is called.\n" \
356 "It can be used to rotate, flip and replace sprites while the game is running.\n" \
357 "Unlike mset, which saves changes to the map, this special function can be used to create " \
358 "animated tiles or replace them completely.\n" \
359 "Some examples include changing sprites to open doorways, " \
360 "hiding sprites used to spawn objects in your game and even to emit the objects themselves.\n" \
361 "The tilemap is laid out sequentially in RAM - writing 1 to 0x08000 " \
362 "will cause tile(sprite) #1 to appear at top left when map() is called.\n" \
363 "To set the tile immediately below this we need to write to 0x08000 + 240, ie 0x080F0.", \
364 9, \
365 0, \
366 1, \
367 void, \
368 tic_mem*, s32 x, s32 y, s32 width, s32 height, s32 sx, s32 sy, \
369 u8* trans_colors, u8 trans_count, s32 scale, RemapFunc remap, void* data) \
370 \
371 \
372 macro(mget, \
373 "mget(x y) -> tile_id", \
374 \
375 "Gets the sprite id at the given x and y map coordinate.", \
376 2, \
377 2, \
378 0, \
379 u8, \
380 tic_mem*, s32 x, s32 y) \
381 \
382 \
383 macro(mset, \
384 "mset(x y tile_id)", \
385 \
386 "This function will change the tile at the specified map coordinates.\n" \
387 "By default, changes made are only kept while the current game is running.\n" \
388 "To make permanent changes to the map, see `sync()`.\n" \
389 "Related: `map()` `mget()` `sync()`.", \
390 3, \
391 3, \
392 0, \
393 void, \
394 tic_mem*, s32 x, s32 y, u8 value) \
395 \
396 \
397 macro(peek, \
398 "peek(addr bits=8) -> value", \
399 \
400 "This function allows to read the memory from TIC.\n" \
401 "It's useful to access resources created with the integrated tools like sprite, maps, sounds, " \
402 "cartridges data?\n" \
403 "Never dream to sound a sprite?\n" \
404 "Address are in hexadecimal format but values are decimal.\n" \
405 "To write to a memory address, use `poke()`.\n" \
406 "`bits` allowed to be 1,2,4,8.", \
407 2, \
408 1, \
409 0, \
410 u8, \
411 tic_mem*, s32 address, s32 bits) \
412 \
413 \
414 macro(poke, \
415 "poke(addr value bits=8)", \
416 \
417 "This function allows you to write a single byte to any address in TIC's RAM.\n" \
418 "The address should be specified in hexadecimal format, the value in decimal.\n" \
419 "`bits` allowed to be 1,2,4,8.", \
420 3, \
421 2, \
422 0, \
423 void, \
424 tic_mem*, s32 address, u8 value, s32 bits) \
425 \
426 \
427 macro(peek1, \
428 "peek1(addr) -> value", \
429 \
430 "This function enables you to read single bit values from TIC's RAM.\n" \
431 "The address is often specified in hexadecimal format.", \
432 1, \
433 1, \
434 0, \
435 u8, \
436 tic_mem*, s32 address) \
437 \
438 \
439 macro(poke1, \
440 "poke1(addr value)", \
441 \
442 "This function allows you to write single bit values directly to RAM.\n" \
443 "The address is often specified in hexadecimal format.", \
444 2, \
445 2, \
446 0, \
447 void, \
448 tic_mem*, s32 address, u8 value) \
449 \
450 \
451 macro(peek2, \
452 "peek2(addr) -> value", \
453 \
454 "This function enables you to read two bits values from TIC's RAM.\n" \
455 "The address is often specified in hexadecimal format.", \
456 1, \
457 1, \
458 0, \
459 u8, \
460 tic_mem*, s32 address) \
461 \
462 \
463 macro(poke2, \
464 "poke2(addr value)", \
465 \
466 "This function allows you to write two bits values directly to RAM.\n" \
467 "The address is often specified in hexadecimal format.", \
468 2, \
469 2, \
470 0, \
471 void, \
472 tic_mem*, s32 address, u8 value) \
473 \
474 \
475 macro(peek4, \
476 "peek4(addr) -> value", \
477 \
478 "This function enables you to read values from TIC's RAM.\n" \
479 "The address is often specified in hexadecimal format.\n" \
480 "See 'poke4()' for detailed information on how nibble addressing compares with byte addressing.", \
481 1, \
482 1, \
483 0, \
484 u8, \
485 tic_mem*, s32 address) \
486 \
487 \
488 macro(poke4, \
489 "poke4(addr value)", \
490 \
491 "This function allows you to write directly to RAM.\n" \
492 "The address is often specified in hexadecimal format.\n" \
493 "For both peek4 and poke4 RAM is addressed in 4 bit segments (nibbles).\n" \
494 "Therefore, to access the the RAM at byte address 0x4000\n" \
495 "you would need to access both the 0x8000 and 0x8001 nibble addresses.", \
496 2, \
497 2, \
498 0, \
499 void, \
500 tic_mem*, s32 address, u8 value) \
501 \
502 \
503 macro(memcpy, \
504 "memcpy(dest source size)", \
505 \
506 "This function allows you to copy a continuous block of TIC's 96K RAM from one address to another.\n" \
507 "Addresses are specified are in hexadecimal format, values are decimal.", \
508 3, \
509 3, \
510 0, \
511 void, \
512 tic_mem*, s32 dst, s32 src, s32 size) \
513 \
514 \
515 macro(memset, \
516 "memset(dest value size)", \
517 \
518 "This function allows you to set a continuous block of any part of TIC's RAM to the same value.\n" \
519 "The address is specified in hexadecimal format, the value in decimal.", \
520 3, \
521 3, \
522 0, \
523 void, \
524 tic_mem*, s32 dst, u8 val, s32 size) \
525 \
526 \
527 macro(trace, \
528 "trace(message color=15)", \
529 \
530 "This is a service function, useful for debugging your code.\n" \
531 "It prints the message parameter to the console in the (optional) color specified.\n" \
532 "\nTips:\n" \
533 "- The Lua concatenator for strings is .. (two points).\n" \
534 "- Use console cls command to clear the output from trace.", \
535 2, \
536 1, \
537 0, \
538 void, \
539 tic_mem*, const char* text, u8 color) \
540 \
541 \
542 macro(pmem, \
543 "pmem(index value)\npmem(index) -> value", \
544 \
545 "This function allows you to save and retrieve data in one of the 256 individual 32-bit slots " \
546 "available in the cartridge's persistent memory.\n" \
547 "This is useful for saving high-scores, level advancement or achievements.\n" \
548 "The data is stored as unsigned 32-bit integers (from 0 to 4294967295).\n" \
549 "\nTips:\n" \
550 "- pmem depends on the cartridge hash (md5), so don't change your lua script if you want to keep the data.\n" \
551 "- Use `saveid:` with a personalized string in the header metadata to override the default MD5 calculation.\n" \
552 "This allows the user to update a cart without losing their saved data.", \
553 2, \
554 1, \
555 0, \
556 u32, \
557 tic_mem*, s32 index, u32 value, bool get) \
558 \
559 \
560 macro(time, \
561 "time() -> ticks", \
562 \
563 "This function returns the number of milliseconds elapsed since the cartridge began execution.\n" \
564 "Useful for keeping track of time, animating items and triggering events.", \
565 0, \
566 0, \
567 0, \
568 double, \
569 tic_mem*) \
570 \
571 \
572 macro(tstamp, \
573 "tstamp() -> timestamp", \
574 \
575 "This function returns the number of seconds elapsed since January 1st, 1970.\n" \
576 "Useful for creating persistent games which evolve over time between plays.", \
577 0, \
578 0, \
579 0, \
580 s32, \
581 tic_mem*) \
582 \
583 \
584 macro(exit, \
585 "exit()", \
586 \
587 "Interrupts program execution and returns to the console when the TIC function ends.", \
588 0, \
589 0, \
590 0, \
591 void, \
592 tic_mem*) \
593 \
594 \
595 macro(font, \
596 "font(text x y chromakey char_width char_height fixed=false scale=1) -> width", \
597 \
598 "Print string with font defined in foreground sprites.\n" \
599 "To simply print to the screen, check out `print()`.\n" \
600 "To print to the console, check out `trace()`.", \
601 8, \
602 6, \
603 0, \
604 s32, \
605 tic_mem*, const char* text, s32 x, s32 y, \
606 u8* trans_colors, u8 trans_count, s32 w, s32 h, bool fixed, s32 scale, bool alt) \
607 \
608 \
609 macro(mouse, \
610 "mouse() -> x y left middle right scrollx scrolly", \
611 \
612 "This function returns the mouse coordinates and a boolean value for the state of each mouse button," \
613 "with true indicating that a button is pressed.", \
614 0, \
615 0, \
616 0, \
617 tic_point, \
618 tic_mem*) \
619 \
620 \
621 macro(circ, \
622 "circ(x y radius color)", \
623 \
624 "This function draws a filled circle of the desired radius and color with its center at x, y.\n" \
625 "It uses the Bresenham algorithm.", \
626 4, \
627 4, \
628 0, \
629 void, \
630 tic_mem*, s32 x, s32 y, s32 radius, u8 color) \
631 \
632 \
633 macro(circb, \
634 "circb(x y radius color)", \
635 \
636 "Draws the circumference of a circle with its center at x, y using the radius and color requested.\n" \
637 "It uses the Bresenham algorithm.", \
638 4, \
639 4, \
640 0, \
641 void, \
642 tic_mem*, s32 x, s32 y, s32 radius, u8 color) \
643 \
644 \
645 macro(elli, \
646 "elli(x y a b color)", \
647 \
648 "This function draws a filled ellipse of the desired a, b radiuses and color with its center at x, y.\n" \
649 "It uses the Bresenham algorithm.", \
650 5, \
651 5, \
652 0, \
653 void, \
654 tic_mem*, s32 x, s32 y, s32 a, s32 b, u8 color) \
655 \
656 \
657 macro(ellib, \
658 "ellib(x y a b color)", \
659 \
660 "This function draws an ellipse border with the desired radiuses a b and color with its center at x, y.\n" \
661 "It uses the Bresenham algorithm.", \
662 5, \
663 5, \
664 0, \
665 void, \
666 tic_mem*, s32 x, s32 y, s32 a, s32 b, u8 color) \
667 \
668 \
669 macro(tri, \
670 "tri(x1 y1 x2 y2 x3 y3 color)", \
671 \
672 "This function draws a triangle filled with color, using the supplied vertices.", \
673 7, \
674 7, \
675 0, \
676 void, \
677 tic_mem*, float x1, float y1, float x2, float y2, float x3, float y3, u8 color) \
678 \
679 macro(trib, \
680 "trib(x1 y1 x2 y2 x3 y3 color)", \
681 \
682 "This function draws a triangle border with color, using the supplied vertices.", \
683 7, \
684 7, \
685 0, \
686 void, \
687 tic_mem*, float x1, float y1, float x2, float y2, float x3, float y3, u8 color) \
688 \
689 \
690 macro(ttri, \
691 "ttri(x1 y1 x2 y2 x3 y3 u1 v1 u2 v2 u3 v3 texsrc=0 chromakey=-1 z1=0 z2=0 z3=0)", \
692 \
693 "It renders a triangle filled with texture from image ram, map ram or vbank.\n" \
694 "Use in 3D graphics.\n" \
695 "In particular, if the vertices in the triangle have different 3D depth, you may see some distortion.\n" \
696 "These can be thought of as the window inside image ram (sprite sheet), map ram or another vbank.\n" \
697 "Note that the sprite sheet or map in this case is treated as a single large image, " \
698 "with U and V addressing its pixels directly, rather than by sprite ID.\n" \
699 "So for example the top left corner of sprite #2 would be located at u=16, v=0.", \
700 17, \
701 12, \
702 0, \
703 void, \
704 tic_mem*, float x1, float y1, float x2, float y2, float x3, float y3, \
705 float u1, float v1, float u2, float v2, float u3, float v3, tic_texture_src texsrc, u8* colors, s32 count, \
706 float z1, float z2, float z3, bool depth) \
707 \
708 \
709 macro(clip, \
710 "clip(x y width height)\nclip()", \
711 \
712 "This function limits drawing to a clipping region or `viewport` defined by x,y,w,h.\n" \
713 "Things drawn outside of this area will not be visible.\n" \
714 "Calling clip() with no parameters will reset the drawing area to the entire screen.", \
715 4, \
716 4, \
717 0, \
718 void, \
719 tic_mem*, s32 x, s32 y, s32 width, s32 height) \
720 \
721 \
722 macro(music, \
723 "music(track=-1 frame=-1 row=-1 loop=true sustain=false tempo=-1 speed=-1)", \
724 \
725 "This function starts playing a track created in the Music Editor.\n" \
726 "Call without arguments to stop the music.", \
727 7, \
728 0, \
729 0, \
730 void, \
731 tic_mem*, s32 track, s32 frame, s32 row, bool loop, bool sustain, s32 tempo, s32 speed) \
732 \
733 \
734 macro(sync, \
735 "sync(mask=0 bank=0 tocart=false)", \
736 \
737 "The pro version of TIC-80 contains 8 memory banks.\n" \
738 "To switch between these banks, sync can be used to either load contents from a memory bank to runtime, " \
739 "or save contents from the active runtime to a bank.\n" \
740 "The function can only be called once per frame." \
741 "If you have manipulated the runtime memory (e.g. by using mset), " \
742 "you can reset the active state by calling sync(0,0,false).\n" \
743 "This resets the whole runtime memory to the contents of bank 0." \
744 "Note that sync is not used to load code from banks; this is done automatically.", \
745 3, \
746 0, \
747 0, \
748 void, \
749 tic_mem*, u32 mask, s32 bank, bool toCart) \
750 \
751 \
752 macro(vbank, \
753 "vbank(bank) -> prev\nvbank() -> prev", \
754 \
755 "VRAM contains 2x16K memory chips, use vbank(0) or vbank(1) to switch between them.", \
756 1, \
757 1, \
758 0, \
759 s32, \
760 tic_mem*, s32 bank) \
761 \
762 \
763 macro(reset, \
764 "reset()", \
765 \
766 "Resets the cartridge. To return to the console, see the `exit()`.", \
767 0, \
768 0, \
769 0, \
770 void, \
771 tic_mem*) \
772 \
773 \
774 macro(key, \
775 "key(code=-1) -> pressed", \
776 \
777 "The function returns true if the key denoted by keycode is pressed.", \
778 1, \
779 0, \
780 0, \
781 bool, \
782 tic_mem*, tic_key key) \
783 \
784 \
785 macro(keyp, \
786 "keyp(code=-1 hold=-1 period=-1) -> pressed", \
787 \
788 "This function returns true if the given key is pressed but wasn't pressed in the previous frame.\n" \
789 "Refer to `btnp()` for an explanation of the optional hold and period parameters.", \
790 3, \
791 0, \
792 0, \
793 bool, \
794 tic_mem*, tic_key key, s32 hold, s32 period) \
795 \
796 \
797 macro(fget, \
798 "fget(sprite_id flag) -> bool", \
799 \
800 "Returns true if the specified flag of the sprite is set. See `fset()` for more details.", \
801 2, \
802 2, \
803 0, \
804 bool, \
805 tic_mem*, s32 index, u8 flag) \
806 \
807 \
808 macro(fset, \
809 "fset(sprite_id flag bool)", \
810 \
811 "Each sprite has eight flags which can be used to store information or signal different conditions.\n" \
812 "For example, flag 0 might be used to indicate that the sprite is invisible, " \
813 "flag 6 might indicate that the flag should be draw scaled etc.\n" \
814 "See algo `fget()`.", \
815 3, \
816 3, \
817 0, \
818 void, \
819 tic_mem*, s32 index, u8 flag, bool value)
820
821#define TIC_API_DEF(name, _, __, ___, ____, _____, ret, ...) ret tic_api_##name(__VA_ARGS__);
822TIC_API_LIST(TIC_API_DEF)
823#undef TIC_API_DEF
824
825struct tic_mem
826{
827 tic80 product;
828 tic_ram* ram;
829 tic_cartridge cart;
830
831 tic_ram* base_ram;
832
833 char saveid[TIC_SAVEID_SIZE];
834
835 union
836 {
837 struct
838 {
839#if RETRO_IS_BIG_ENDIAN
840 u8 padded:5;
841 u8 keyboard:1;
842 u8 mouse:1;
843 u8 gamepad:1;
844#else
845 u8 gamepad:1;
846 u8 mouse:1;
847 u8 keyboard:1;
848 u8 padded:5;
849#endif
850 };
851
852 u8 data;
853 } input;
854};
855
856tic_mem* tic_core_create(s32 samplerate, tic80_pixel_color_format format);
857void tic_core_close(tic_mem* memory);
858void tic_core_pause(tic_mem* memory);
859void tic_core_resume(tic_mem* memory);
860void tic_core_tick_start(tic_mem* memory);
861void tic_core_tick(tic_mem* memory, tic_tick_data* data);
862void tic_core_tick_end(tic_mem* memory);
863void tic_core_synth_sound(tic_mem* tic);
864void tic_core_blit(tic_mem* tic);
865void tic_core_blit_ex(tic_mem* tic, tic_blit_callback clb);
866const tic_script_config* tic_core_script_config(tic_mem* memory);
867
868#define VBANK(tic, bank) \
869 bool MACROVAR(_bank_) = tic_api_vbank(tic, bank); \
870 SCOPE(tic_api_vbank(tic, MACROVAR(_bank_)))
871