this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

#1111: split tic.c to modules

Nesbox ba603ba6 0f5a8364

+3263 -3156
+26 -24
CMakeLists.txt
··· 317 317 318 318 set(TIC80CORE_DIR ${CMAKE_SOURCE_DIR}/src) 319 319 set(TIC80CORE_SRC 320 - ${TIC80CORE_DIR}/core/tic80.c 321 - ${TIC80CORE_DIR}/core/tic.c 322 - ${TIC80CORE_DIR}/core/cart.c 323 - ${TIC80CORE_DIR}/core/tilesheet.c 320 + ${TIC80CORE_DIR}/core/core.c 321 + ${TIC80CORE_DIR}/core/draw.c 322 + ${TIC80CORE_DIR}/core/io.c 323 + ${TIC80CORE_DIR}/core/sound.c 324 324 ${TIC80CORE_DIR}/api/js.c 325 325 ${TIC80CORE_DIR}/api/lua.c 326 326 ${TIC80CORE_DIR}/api/wren.c 327 327 ${TIC80CORE_DIR}/api/squirrel.c 328 - ${TIC80CORE_DIR}/ext/gif.c 328 + ${TIC80CORE_DIR}/ext/gif.c 329 + ${TIC80CORE_DIR}/tic.c 330 + ${TIC80CORE_DIR}/cart.c 329 331 ${TIC80CORE_DIR}/tools.c 332 + ${TIC80CORE_DIR}/tilesheet.c 330 333 ) 331 334 332 335 add_library(tic80core STATIC ${TIC80CORE_SRC}) ··· 389 392 ################################ 390 393 391 394 if(BUILD_SOKOL) 392 - set(SOKOL_LIB_SRC ${CMAKE_SOURCE_DIR}/src/system/sokol_gfx.c) 395 + set(SOKOL_LIB_SRC ${CMAKE_SOURCE_DIR}/src/system/sokol/sokol_gfx.c) 393 396 394 397 if(APPLE) 395 - set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol_impl.m) 398 + set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol/sokol_impl.m) 396 399 else() 397 - set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol_impl.c) 400 + set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol/sokol_impl.c) 398 401 endif() 399 402 400 403 add_library(sokol STATIC ${SOKOL_LIB_SRC}) ··· 625 628 626 629 set(TIC80LIB_DIR ${CMAKE_SOURCE_DIR}/src) 627 630 set(TIC80LIB_SRC 631 + ${TIC80LIB_DIR}/studio/screens/console.c 632 + ${TIC80LIB_DIR}/studio/screens/run.c 633 + ${TIC80LIB_DIR}/studio/screens/dialog.c 634 + ${TIC80LIB_DIR}/studio/screens/menu.c 635 + ${TIC80LIB_DIR}/studio/screens/surf.c 636 + ${TIC80LIB_DIR}/studio/screens/start.c 637 + ${TIC80LIB_DIR}/studio/editors/code.c 638 + ${TIC80LIB_DIR}/studio/editors/sprite.c 639 + ${TIC80LIB_DIR}/studio/editors/map.c 640 + ${TIC80LIB_DIR}/studio/editors/world.c 641 + ${TIC80LIB_DIR}/studio/editors/sfx.c 642 + ${TIC80LIB_DIR}/studio/editors/music.c 628 643 ${TIC80LIB_DIR}/studio/studio.c 629 - ${TIC80LIB_DIR}/studio/console.c 630 - ${TIC80LIB_DIR}/studio/run.c 631 - ${TIC80LIB_DIR}/studio/fs.c 632 - ${TIC80LIB_DIR}/studio/start.c 633 - ${TIC80LIB_DIR}/studio/sprite.c 634 - ${TIC80LIB_DIR}/studio/map.c 635 - ${TIC80LIB_DIR}/studio/sfx.c 636 - ${TIC80LIB_DIR}/studio/music.c 637 - ${TIC80LIB_DIR}/studio/world.c 638 644 ${TIC80LIB_DIR}/studio/config.c 639 - ${TIC80LIB_DIR}/studio/code.c 640 - ${TIC80LIB_DIR}/studio/dialog.c 641 - ${TIC80LIB_DIR}/studio/menu.c 642 - ${TIC80LIB_DIR}/studio/surf.c 643 645 ${TIC80LIB_DIR}/studio/project.c 646 + ${TIC80LIB_DIR}/studio/fs.c 644 647 ${TIC80LIB_DIR}/ext/md5.c 645 648 ${TIC80LIB_DIR}/ext/gif.c 646 649 ${TIC80LIB_DIR}/ext/history.c 647 650 ${TIC80LIB_DIR}/ext/net.c 648 - ${TIC80LIB_DIR}/tools.c 649 651 ) 650 652 651 653 set(TIC80_OUTPUT tic80) ··· 763 765 set(TIC80_SRC ${TIC80_SRC} ${CMAKE_SOURCE_DIR}/src/ext/file_dialog.m) 764 766 endif() 765 767 766 - set(TIC80_SRC ${TIC80_SRC} src/system/sdlgpu.c) 768 + set(TIC80_SRC ${TIC80_SRC} src/system/sdl/sdlgpu.c) 767 769 768 770 if(WIN32) 769 771 ··· 846 848 set(TIC80_SRC ${TIC80_SRC} ${CMAKE_SOURCE_DIR}/src/ext/file_dialog.m) 847 849 endif() 848 850 849 - set(TIC80_SRC ${TIC80_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol.c) 851 + set(TIC80_SRC ${TIC80_SRC} ${CMAKE_SOURCE_DIR}/src/system/sokol/sokol.c) 850 852 851 853 if(WIN32) 852 854
+6
build/android/app/build.gradle
··· 8 8 targetSdkVersion 26 9 9 versionCode 9000 10 10 versionName '0.90.00' 11 + 12 + externalNativeBuild { 13 + cmake { 14 + arguments "-DBUILD_PRO=Off" 15 + } 16 + } 11 17 } 12 18 13 19 signingConfigs {
+1 -1
src/api.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "core/tic.h" 25 + #include "tic.h" 26 26 27 27 typedef struct { u8 index; tic_flip flip; tic_rotate rotate; } RemapResult; 28 28 typedef void(*RemapFunc)(void*, s32 x, s32 y, RemapResult* result);
+79 -79
src/api/js.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "core/machine.h" 23 + #include "core/core.h" 24 24 25 25 #if defined(TIC_BUILD_WITH_JS) 26 26 ··· 30 30 31 31 #include "duktape.h" 32 32 33 - static const char TicMachine[] = "_TIC80"; 33 + static const char TicCore[] = "_TIC80"; 34 34 35 35 static void closeJavascript(tic_mem* tic) 36 36 { 37 - tic_machine* machine = (tic_machine*)tic; 37 + tic_core* core = (tic_core*)tic; 38 38 39 - if(machine->js) 39 + if(core->js) 40 40 { 41 - duk_destroy_heap(machine->js); 42 - machine->js = NULL; 41 + duk_destroy_heap(core->js); 42 + core->js = NULL; 43 43 } 44 44 } 45 45 46 - static tic_machine* getDukMachine(duk_context* duk) 46 + static tic_core* getDukCore(duk_context* duk) 47 47 { 48 48 duk_push_global_stash(duk); 49 - duk_get_prop_string(duk, -1, TicMachine); 50 - tic_machine* machine = duk_to_pointer(duk, -1); 49 + duk_get_prop_string(duk, -1, TicCore); 50 + tic_core* core = duk_to_pointer(duk, -1); 51 51 duk_pop_2(duk); 52 52 53 - return machine; 53 + return core; 54 54 } 55 55 56 56 static duk_ret_t duk_print(duk_context* duk) 57 57 { 58 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 58 + tic_mem* tic = (tic_mem*)getDukCore(duk); 59 59 60 60 const char* text = duk_to_string(duk, 0); 61 61 s32 x = duk_opt_int(duk, 1, 0); ··· 74 74 75 75 static duk_ret_t duk_cls(duk_context* duk) 76 76 { 77 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 77 + tic_mem* tic = (tic_mem*)getDukCore(duk); 78 78 79 79 tic_api_cls(tic, duk_opt_int(duk, 0, 0)); 80 80 ··· 86 86 s32 x = duk_to_int(duk, 0); 87 87 s32 y = duk_to_int(duk, 1); 88 88 89 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 89 + tic_mem* tic = (tic_mem*)getDukCore(duk); 90 90 91 91 if(duk_is_null_or_undefined(duk, 2)) 92 92 { ··· 110 110 s32 y1 = duk_to_int(duk, 3); 111 111 s32 color = duk_to_int(duk, 4); 112 112 113 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 113 + tic_mem* tic = (tic_mem*)getDukCore(duk); 114 114 115 115 tic_api_line(tic, x0, y0, x1, y1, color); 116 116 ··· 125 125 s32 h = duk_to_int(duk, 3); 126 126 s32 color = duk_to_int(duk, 4); 127 127 128 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 128 + tic_mem* tic = (tic_mem*)getDukCore(duk); 129 129 tic_api_rect(tic, x, y, w, h, color); 130 130 131 131 return 0; ··· 139 139 s32 h = duk_to_int(duk, 3); 140 140 s32 color = duk_to_int(duk, 4); 141 141 142 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 142 + tic_mem* tic = (tic_mem*)getDukCore(duk); 143 143 tic_api_rectb(tic, x, y, w, h, color); 144 144 145 145 return 0; ··· 189 189 s32 w = duk_opt_int(duk, 7, 1); 190 190 s32 h = duk_opt_int(duk, 8, 1); 191 191 192 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 192 + tic_mem* tic = (tic_mem*)getDukCore(duk); 193 193 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); 194 194 195 195 return 0; ··· 197 197 198 198 static duk_ret_t duk_btn(duk_context* duk) 199 199 { 200 - tic_machine* machine = getDukMachine(duk); 200 + tic_core* core = getDukCore(duk); 201 201 202 202 if (duk_is_null_or_undefined(duk, 0)) 203 203 { 204 - duk_push_uint(duk, machine->memory.ram.input.gamepads.data); 204 + duk_push_uint(duk, core->memory.ram.input.gamepads.data); 205 205 } 206 206 else 207 207 { 208 208 s32 index = duk_to_int(duk, 0) & 0x1f; 209 - duk_push_boolean(duk, machine->memory.ram.input.gamepads.data & (1 << index)); 209 + duk_push_boolean(duk, core->memory.ram.input.gamepads.data & (1 << index)); 210 210 } 211 211 212 212 return 1; ··· 214 214 215 215 static duk_ret_t duk_btnp(duk_context* duk) 216 216 { 217 - tic_machine* machine = getDukMachine(duk); 218 - tic_mem* tic = (tic_mem*)machine; 217 + tic_core* core = getDukCore(duk); 218 + tic_mem* tic = (tic_mem*)core; 219 219 220 220 if (duk_is_null_or_undefined(duk, 0)) 221 221 { ··· 241 241 242 242 static s32 duk_key(duk_context* duk) 243 243 { 244 - tic_machine* machine = getDukMachine(duk); 245 - tic_mem* tic = &machine->memory; 244 + tic_core* core = getDukCore(duk); 245 + tic_mem* tic = &core->memory; 246 246 247 247 if (duk_is_null_or_undefined(duk, 0)) 248 248 { ··· 262 262 263 263 static s32 duk_keyp(duk_context* duk) 264 264 { 265 - tic_machine* machine = getDukMachine(duk); 266 - tic_mem* tic = &machine->memory; 265 + tic_core* core = getDukCore(duk); 266 + tic_mem* tic = &core->memory; 267 267 268 268 if (duk_is_null_or_undefined(duk, 0)) 269 269 { ··· 298 298 299 299 static duk_ret_t duk_sfx(duk_context* duk) 300 300 { 301 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 301 + tic_mem* tic = (tic_mem*)getDukCore(duk); 302 302 303 303 s32 index = duk_opt_int(duk, 0, -1); 304 304 ··· 437 437 } 438 438 } 439 439 440 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 440 + tic_mem* tic = (tic_mem*)getDukCore(duk); 441 441 442 442 if (duk_is_null_or_undefined(duk, 8)) 443 443 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); ··· 447 447 448 448 RemapData data = {duk, remap}; 449 449 450 - tic_api_map((tic_mem*)getDukMachine(duk), x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); 450 + tic_api_map((tic_mem*)getDukCore(duk), x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); 451 451 } 452 452 453 453 return 0; ··· 458 458 s32 x = duk_opt_int(duk, 0, 0); 459 459 s32 y = duk_opt_int(duk, 1, 0); 460 460 461 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 461 + tic_mem* tic = (tic_mem*)getDukCore(duk); 462 462 463 463 u8 value = tic_api_mget(tic, x, y); 464 464 duk_push_uint(duk, value); ··· 471 471 s32 y = duk_opt_int(duk, 1, 0); 472 472 u8 value = duk_opt_int(duk, 2, 0); 473 473 474 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 474 + tic_mem* tic = (tic_mem*)getDukCore(duk); 475 475 476 476 tic_api_mset(tic, x, y, value); 477 477 ··· 482 482 { 483 483 s32 address = duk_to_int(duk, 0); 484 484 485 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 485 + tic_mem* tic = (tic_mem*)getDukCore(duk); 486 486 duk_push_uint(duk, tic_api_peek(tic, address)); 487 487 return 1; 488 488 } ··· 492 492 s32 address = duk_to_int(duk, 0); 493 493 u8 value = duk_to_int(duk, 1); 494 494 495 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 495 + tic_mem* tic = (tic_mem*)getDukCore(duk); 496 496 tic_api_poke(tic, address, value); 497 497 498 498 return 0; ··· 502 502 { 503 503 s32 address = duk_to_int(duk, 0); 504 504 505 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 505 + tic_mem* tic = (tic_mem*)getDukCore(duk); 506 506 duk_push_uint(duk, tic_api_peek4(tic, address)); 507 507 return 1; 508 508 } ··· 512 512 s32 address = duk_to_int(duk, 0); 513 513 u8 value = duk_to_int(duk, 1); 514 514 515 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 515 + tic_mem* tic = (tic_mem*)getDukCore(duk); 516 516 tic_api_poke4(tic, address, value); 517 517 518 518 return 0; ··· 524 524 s32 src = duk_to_int(duk, 1); 525 525 s32 size = duk_to_int(duk, 2); 526 526 527 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 527 + tic_mem* tic = (tic_mem*)getDukCore(duk); 528 528 tic_api_memcpy(tic, dest, src, size); 529 529 530 530 return 0; ··· 536 536 u8 value = duk_to_int(duk, 1); 537 537 s32 size = duk_to_int(duk, 2); 538 538 539 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 539 + tic_mem* tic = (tic_mem*)getDukCore(duk); 540 540 tic_api_memset(tic, dest, value, size); 541 541 542 542 return 0; ··· 544 544 545 545 static duk_ret_t duk_trace(duk_context* duk) 546 546 { 547 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 547 + tic_mem* tic = (tic_mem*)getDukCore(duk); 548 548 549 549 const char* text = duk_opt_string(duk, 0, ""); 550 550 u8 color = duk_opt_int(duk, 1, tic_color_12); ··· 556 556 557 557 static duk_ret_t duk_pmem(duk_context* duk) 558 558 { 559 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 559 + tic_mem* tic = (tic_mem*)getDukCore(duk); 560 560 u32 index = duk_to_int(duk, 0); 561 561 562 562 if(index < TIC_PERSISTENT_SIZE) ··· 579 579 580 580 static duk_ret_t duk_time(duk_context* duk) 581 581 { 582 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 582 + tic_mem* tic = (tic_mem*)getDukCore(duk); 583 583 584 584 duk_push_number(duk, tic_api_time(tic)); 585 585 ··· 588 588 589 589 static duk_ret_t duk_tstamp(duk_context* duk) 590 590 { 591 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 591 + tic_mem* tic = (tic_mem*)getDukCore(duk); 592 592 593 593 duk_push_number(duk, tic_api_tstamp(tic)); 594 594 ··· 597 597 598 598 static duk_ret_t duk_exit(duk_context* duk) 599 599 { 600 - tic_api_exit((tic_mem*)getDukMachine(duk)); 600 + tic_api_exit((tic_mem*)getDukCore(duk)); 601 601 602 602 return 0; 603 603 } 604 604 605 605 static duk_ret_t duk_font(duk_context* duk) 606 606 { 607 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 607 + tic_mem* tic = (tic_mem*)getDukCore(duk); 608 608 609 609 const char* text = duk_to_string(duk, 0); 610 610 s32 x = duk_to_int(duk, 1); ··· 630 630 631 631 static duk_ret_t duk_mouse(duk_context* duk) 632 632 { 633 - tic_machine* machine = getDukMachine(duk); 633 + tic_core* core = getDukCore(duk); 634 634 635 - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; 635 + const tic80_mouse* mouse = &core->memory.ram.input.mouse; 636 636 637 637 duk_idx_t idx = duk_push_array(duk); 638 638 duk_push_int(duk, mouse->x); ··· 662 662 s32 y = duk_to_int(duk, 1); 663 663 s32 color = duk_to_int(duk, 3); 664 664 665 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 665 + tic_mem* tic = (tic_mem*)getDukCore(duk); 666 666 667 667 tic_api_circ(tic, x, y, radius, color); 668 668 ··· 678 678 s32 y = duk_to_int(duk, 1); 679 679 s32 color = duk_to_int(duk, 3); 680 680 681 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 681 + tic_mem* tic = (tic_mem*)getDukCore(duk); 682 682 683 683 tic_api_circb(tic, x, y, radius, color); 684 684 ··· 694 694 695 695 s32 color = duk_to_int(duk, 6); 696 696 697 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 697 + tic_mem* tic = (tic_mem*)getDukCore(duk); 698 698 699 699 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); 700 700 ··· 707 707 708 708 for (s32 i = 0; i < COUNT_OF(pt); i++) 709 709 pt[i] = (float)duk_to_number(duk, i); 710 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 710 + tic_mem* tic = (tic_mem*)getDukCore(duk); 711 711 bool use_map = duk_opt_boolean(duk, 12, false); 712 712 713 713 static u8 colors[TIC_PALETTE_SIZE]; ··· 761 761 s32 w = duk_opt_int(duk, 2, TIC80_WIDTH); 762 762 s32 h = duk_opt_int(duk, 3, TIC80_HEIGHT); 763 763 764 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 764 + tic_mem* tic = (tic_mem*)getDukCore(duk); 765 765 766 766 tic_api_clip(tic, x, y, w, h); 767 767 ··· 770 770 771 771 static duk_ret_t duk_music(duk_context* duk) 772 772 { 773 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 773 + tic_mem* tic = (tic_mem*)getDukCore(duk); 774 774 775 775 s32 track = duk_opt_int(duk, 0, -1); 776 776 tic_api_music(tic, -1, 0, 0, false, false); ··· 790 790 791 791 static duk_ret_t duk_sync(duk_context* duk) 792 792 { 793 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 793 + tic_mem* tic = (tic_mem*)getDukCore(duk); 794 794 795 795 u32 mask = duk_opt_int(duk, 0, 0); 796 796 s32 bank = duk_opt_int(duk, 1, 0); ··· 806 806 807 807 static duk_ret_t duk_reset(duk_context* duk) 808 808 { 809 - tic_machine* machine = getDukMachine(duk); 809 + tic_core* core = getDukCore(duk); 810 810 811 - machine->state.initialized = false; 811 + core->state.initialized = false; 812 812 813 813 return 0; 814 814 } 815 815 816 816 static duk_ret_t duk_fget(duk_context* duk) 817 817 { 818 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 818 + tic_mem* tic = (tic_mem*)getDukCore(duk); 819 819 820 820 u32 index = duk_opt_int(duk, 0, 0); 821 821 u32 flag = duk_opt_int(duk, 1, 0); ··· 829 829 830 830 static duk_ret_t duk_fset(duk_context* duk) 831 831 { 832 - tic_mem* tic = (tic_mem*)getDukMachine(duk); 832 + tic_mem* tic = (tic_mem*)getDukCore(duk); 833 833 834 834 u32 index = duk_opt_int(duk, 0, 0); 835 835 u32 flag = duk_opt_int(duk, 1, 0); ··· 844 844 845 845 s32 duk_timeout_check(void* udata) 846 846 { 847 - tic_machine* machine = (tic_machine*)udata; 848 - tic_tick_data* tick = machine->data; 847 + tic_core* core = (tic_core*)udata; 848 + tic_tick_data* tick = core->data; 849 849 850 850 return ForceExitCounter++ > 1000 ? tick->forceExit && tick->forceExit(tick->data) : false; 851 851 } 852 852 853 - static void initDuktape(tic_machine* machine) 853 + static void initDuktape(tic_core* core) 854 854 { 855 - closeJavascript((tic_mem*)machine); 855 + closeJavascript((tic_mem*)core); 856 856 857 - duk_context* duk = machine->js = duk_create_heap(NULL, NULL, NULL, machine, NULL); 857 + duk_context* duk = core->js = duk_create_heap(NULL, NULL, NULL, core, NULL); 858 858 859 859 { 860 860 duk_push_global_stash(duk); 861 - duk_push_pointer(duk, machine); 862 - duk_put_prop_string(duk, -2, TicMachine); 861 + duk_push_pointer(duk, core); 862 + duk_put_prop_string(duk, -2, TicCore); 863 863 duk_pop(duk); 864 864 } 865 865 ··· 869 869 870 870 for (s32 i = 0; i < COUNT_OF(ApiItems); i++) 871 871 { 872 - duk_push_c_function(machine->js, ApiItems[i].func, ApiItems[i].params); 873 - duk_put_global_string(machine->js, ApiItems[i].name); 872 + duk_push_c_function(core->js, ApiItems[i].func, ApiItems[i].params); 873 + duk_put_global_string(core->js, ApiItems[i].name); 874 874 } 875 875 } 876 876 877 877 static bool initJavascript(tic_mem* tic, const char* code) 878 878 { 879 - tic_machine* machine = (tic_machine*)tic; 879 + tic_core* core = (tic_core*)tic; 880 880 881 - initDuktape(machine); 882 - duk_context* duktape = machine->js; 881 + initDuktape(core); 882 + duk_context* duktape = core->js; 883 883 884 884 if (duk_pcompile_string(duktape, 0, code) != 0 || duk_peval_string(duktape, code) != 0) 885 885 { 886 - machine->data->error(machine->data->data, duk_safe_to_stacktrace(duktape, -1)); 886 + core->data->error(core->data->data, duk_safe_to_stacktrace(duktape, -1)); 887 887 duk_pop(duktape); 888 888 return false; 889 889 } ··· 895 895 { 896 896 ForceExitCounter = 0; 897 897 898 - tic_machine* machine = (tic_machine*)tic; 898 + tic_core* core = (tic_core*)tic; 899 899 900 - duk_context* duk = machine->js; 900 + duk_context* duk = core->js; 901 901 902 902 if(duk) 903 903 { ··· 905 905 { 906 906 if(duk_pcall(duk, 0) != DUK_EXEC_SUCCESS) 907 907 { 908 - machine->data->error(machine->data->data, duk_safe_to_stacktrace(duk, -1)); 908 + core->data->error(core->data->data, duk_safe_to_stacktrace(duk, -1)); 909 909 } 910 910 } 911 - else machine->data->error(machine->data->data, "'function TIC()...' isn't found :("); 911 + else core->data->error(core->data->data, "'function TIC()...' isn't found :("); 912 912 913 913 duk_pop(duk); 914 914 } ··· 916 916 917 917 static void callJavascriptScanlineName(tic_mem* tic, s32 row, void* data, const char* name) 918 918 { 919 - tic_machine* machine = (tic_machine*)tic; 920 - duk_context* duk = machine->js; 919 + tic_core* core = (tic_core*)tic; 920 + duk_context* duk = core->js; 921 921 922 922 if(duk_get_global_string(duk, name)) 923 923 { 924 924 duk_push_int(duk, row); 925 925 926 926 if(duk_pcall(duk, 1) != 0) 927 - machine->data->error(machine->data->data, duk_safe_to_stacktrace(duk, -1)); 927 + core->data->error(core->data->data, duk_safe_to_stacktrace(duk, -1)); 928 928 } 929 929 930 930 duk_pop(duk); ··· 940 940 941 941 static void callJavascriptOverline(tic_mem* tic, void* data) 942 942 { 943 - tic_machine* machine = (tic_machine*)tic; 944 - duk_context* duk = machine->js; 943 + tic_core* core = (tic_core*)tic; 944 + duk_context* duk = core->js; 945 945 946 946 if(duk_get_global_string(duk, OVR_FN)) 947 947 { 948 948 if(duk_pcall(duk, 0) != 0) 949 - machine->data->error(machine->data->data, duk_safe_to_stacktrace(duk, -1)); 949 + core->data->error(core->data->data, duk_safe_to_stacktrace(duk, -1)); 950 950 } 951 951 952 952 duk_pop(duk);
+108 -108
src/api/lua.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "core/machine.h" 23 + #include "core/core.h" 24 24 25 25 #if defined(TIC_BUILD_WITH_LUA) 26 26 ··· 33 33 34 34 #define LUA_LOC_STACK 1E8 // 100.000.000 35 35 36 - static const char TicMachine[] = "_TIC80"; 36 + static const char TicCore[] = "_TIC80"; 37 37 38 38 s32 luaopen_lpeg(lua_State *lua); 39 39 ··· 43 43 return (s32)lua_tonumber(lua, index); 44 44 } 45 45 46 - static void registerLuaFunction(tic_machine* machine, lua_CFunction func, const char *name) 46 + static void registerLuaFunction(tic_core* core, lua_CFunction func, const char *name) 47 47 { 48 - lua_pushcfunction(machine->lua, func); 49 - lua_setglobal(machine->lua, name); 48 + lua_pushcfunction(core->lua, func); 49 + lua_setglobal(core->lua, name); 50 50 } 51 51 52 - static tic_machine* getLuaMachine(lua_State* lua) 52 + static tic_core* getLuaCore(lua_State* lua) 53 53 { 54 - lua_getglobal(lua, TicMachine); 55 - tic_machine* machine = lua_touserdata(lua, -1); 54 + lua_getglobal(lua, TicCore); 55 + tic_core* core = lua_touserdata(lua, -1); 56 56 lua_pop(lua, 1); 57 - return machine; 57 + return core; 58 58 } 59 59 60 60 static s32 lua_peek(lua_State* lua) 61 61 { 62 62 s32 top = lua_gettop(lua); 63 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 63 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 64 64 65 65 if(top == 1) 66 66 { ··· 76 76 static s32 lua_poke(lua_State* lua) 77 77 { 78 78 s32 top = lua_gettop(lua); 79 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 79 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 80 80 81 81 if(top == 2) 82 82 { ··· 93 93 static s32 lua_peek4(lua_State* lua) 94 94 { 95 95 s32 top = lua_gettop(lua); 96 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 96 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 97 97 98 98 if(top == 1) 99 99 { ··· 109 109 static s32 lua_poke4(lua_State* lua) 110 110 { 111 111 s32 top = lua_gettop(lua); 112 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 112 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 113 113 114 114 if(top == 2) 115 115 { ··· 127 127 { 128 128 s32 top = lua_gettop(lua); 129 129 130 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 130 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 131 131 132 132 tic_api_cls(tic, top == 1 ? getLuaNumber(lua, 1) : 0); 133 133 ··· 143 143 s32 x = getLuaNumber(lua, 1); 144 144 s32 y = getLuaNumber(lua, 2); 145 145 146 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 146 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 147 147 148 148 if(top >= 3) 149 149 { ··· 174 174 s32 y1 = getLuaNumber(lua, 4); 175 175 s32 color = getLuaNumber(lua, 5); 176 176 177 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 177 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 178 178 179 179 tic_api_line(tic, x0, y0, x1, y1, color); 180 180 } ··· 195 195 s32 h = getLuaNumber(lua, 4); 196 196 s32 color = getLuaNumber(lua, 5); 197 197 198 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 198 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 199 199 200 200 tic_api_rect(tic, x, y, w, h, color); 201 201 } ··· 216 216 s32 h = getLuaNumber(lua, 4); 217 217 s32 color = getLuaNumber(lua, 5); 218 218 219 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 219 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 220 220 221 221 tic_api_rectb(tic, x, y, w, h, color); 222 222 } ··· 238 238 s32 y = getLuaNumber(lua, 2); 239 239 s32 color = getLuaNumber(lua, 4); 240 240 241 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 241 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 242 242 243 243 tic_api_circ(tic, x, y, radius, color); 244 244 } ··· 260 260 s32 y = getLuaNumber(lua, 2); 261 261 s32 color = getLuaNumber(lua, 4); 262 262 263 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 263 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 264 264 265 265 tic_api_circb(tic, x, y, radius, color); 266 266 } ··· 282 282 283 283 s32 color = getLuaNumber(lua, 7); 284 284 285 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 285 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 286 286 287 287 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); 288 288 } ··· 302 302 for (s32 i = 0; i < COUNT_OF(pt); i++) 303 303 pt[i] = (float)lua_tonumber(lua, i + 1); 304 304 305 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 305 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 306 306 static u8 colors[TIC_PALETTE_SIZE]; 307 307 s32 count = 0; 308 308 bool use_map = false; ··· 358 358 359 359 if(top == 0) 360 360 { 361 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 361 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 362 362 363 363 tic_api_clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); 364 364 } ··· 369 369 s32 w = getLuaNumber(lua, 3); 370 370 s32 h = getLuaNumber(lua, 4); 371 371 372 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 372 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 373 373 374 - tic_api_clip((tic_mem*)getLuaMachine(lua), x, y, w, h); 374 + tic_api_clip((tic_mem*)getLuaCore(lua), x, y, w, h); 375 375 } 376 376 else luaL_error(lua, "invalid parameters, use clip(x,y,w,h) or clip()\n"); 377 377 ··· 380 380 381 381 static s32 lua_btnp(lua_State* lua) 382 382 { 383 - tic_machine* machine = getLuaMachine(lua); 384 - tic_mem* tic = (tic_mem*)machine; 383 + tic_core* core = getLuaCore(lua); 384 + tic_mem* tic = (tic_mem*)core; 385 385 386 386 s32 top = lua_gettop(lua); 387 387 ··· 414 414 415 415 static s32 lua_btn(lua_State* lua) 416 416 { 417 - tic_machine* machine = getLuaMachine(lua); 417 + tic_core* core = getLuaCore(lua); 418 418 419 419 s32 top = lua_gettop(lua); 420 420 421 421 if (top == 0) 422 422 { 423 - lua_pushinteger(lua, machine->memory.ram.input.gamepads.data); 423 + lua_pushinteger(lua, core->memory.ram.input.gamepads.data); 424 424 } 425 425 else if (top == 1) 426 426 { 427 427 u32 index = getLuaNumber(lua, 1) & 0x1f; 428 - lua_pushboolean(lua, machine->memory.ram.input.gamepads.data & (1 << index)); 428 + lua_pushboolean(lua, core->memory.ram.input.gamepads.data & (1 << index)); 429 429 } 430 430 else 431 431 { ··· 510 510 } 511 511 } 512 512 513 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 513 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 514 514 515 515 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); 516 516 ··· 526 526 s32 x = getLuaNumber(lua, 1); 527 527 s32 y = getLuaNumber(lua, 2); 528 528 529 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 529 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 530 530 531 531 u8 value = tic_api_mget(tic, x, y); 532 532 lua_pushinteger(lua, value); ··· 547 547 s32 y = getLuaNumber(lua, 2); 548 548 u8 val = getLuaNumber(lua, 3); 549 549 550 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 550 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 551 551 552 552 tic_api_mset(tic, x, y, val); 553 553 } ··· 645 645 646 646 RemapData data = {lua, remap}; 647 647 648 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 648 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 649 649 650 650 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); 651 651 ··· 660 660 } 661 661 } 662 662 663 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 663 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 664 664 665 - tic_api_map((tic_mem*)getLuaMachine(lua), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); 665 + tic_api_map((tic_mem*)getLuaCore(lua), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); 666 666 667 667 return 0; 668 668 } ··· 670 670 static s32 lua_music(lua_State* lua) 671 671 { 672 672 s32 top = lua_gettop(lua); 673 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 673 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 674 674 675 675 if(top == 0) tic_api_music(tic, -1, 0, 0, false, false); 676 676 else if(top >= 1) ··· 711 711 712 712 if(top >= 1) 713 713 { 714 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 714 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 715 715 716 716 s32 note = -1; 717 717 s32 octave = -1; ··· 788 788 789 789 static s32 lua_sync(lua_State* lua) 790 790 { 791 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 791 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 792 792 793 793 bool toCart = false; 794 794 u32 mask = 0; ··· 819 819 820 820 static s32 lua_reset(lua_State* lua) 821 821 { 822 - tic_machine* machine = getLuaMachine(lua); 822 + tic_core* core = getLuaCore(lua); 823 823 824 - machine->state.initialized = false; 824 + core->state.initialized = false; 825 825 826 826 return 0; 827 827 } 828 828 829 829 static s32 lua_key(lua_State* lua) 830 830 { 831 - tic_machine* machine = getLuaMachine(lua); 832 - tic_mem* tic = &machine->memory; 831 + tic_core* core = getLuaCore(lua); 832 + tic_mem* tic = &core->memory; 833 833 834 834 s32 top = lua_gettop(lua); 835 835 ··· 860 860 861 861 static s32 lua_keyp(lua_State* lua) 862 862 { 863 - tic_machine* machine = getLuaMachine(lua); 864 - tic_mem* tic = &machine->memory; 863 + tic_core* core = getLuaCore(lua); 864 + tic_mem* tic = &core->memory; 865 865 866 866 s32 top = lua_gettop(lua); 867 867 ··· 911 911 s32 src = getLuaNumber(lua, 2); 912 912 s32 size = getLuaNumber(lua, 3); 913 913 914 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 914 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 915 915 tic_api_memcpy(tic, dest, src, size); 916 916 } 917 917 else luaL_error(lua, "invalid params, memcpy(dest,src,size)\n"); ··· 929 929 u8 value = getLuaNumber(lua, 2); 930 930 s32 size = getLuaNumber(lua, 3); 931 931 932 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 932 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 933 933 tic_api_memset(tic, dest, value, size); 934 934 } 935 935 else luaL_error(lua, "invalid params, memset(dest,val,size)\n"); ··· 953 953 954 954 static s32 lua_font(lua_State* lua) 955 955 { 956 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 956 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 957 957 s32 top = lua_gettop(lua); 958 958 959 959 if(top >= 1) ··· 1022 1022 1023 1023 if(top >= 1) 1024 1024 { 1025 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1025 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1026 1026 1027 1027 s32 x = 0; 1028 1028 s32 y = 0; ··· 1078 1078 static s32 lua_trace(lua_State *lua) 1079 1079 { 1080 1080 s32 top = lua_gettop(lua); 1081 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1081 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1082 1082 1083 1083 if(top >= 1) 1084 1084 { ··· 1100 1100 static s32 lua_pmem(lua_State *lua) 1101 1101 { 1102 1102 s32 top = lua_gettop(lua); 1103 - tic_machine* machine = getLuaMachine(lua); 1104 - tic_mem* tic = &machine->memory; 1103 + tic_core* core = getLuaCore(lua); 1104 + tic_mem* tic = &core->memory; 1105 1105 1106 1106 if(top >= 1) 1107 1107 { ··· 1130 1130 1131 1131 static s32 lua_time(lua_State *lua) 1132 1132 { 1133 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1133 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1134 1134 1135 1135 lua_pushnumber(lua, tic_api_time(tic)); 1136 1136 ··· 1139 1139 1140 1140 static s32 lua_tstamp(lua_State *lua) 1141 1141 { 1142 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1142 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1143 1143 1144 1144 lua_pushnumber(lua, tic_api_tstamp(tic)); 1145 1145 ··· 1148 1148 1149 1149 static s32 lua_exit(lua_State *lua) 1150 1150 { 1151 - tic_api_exit((tic_mem*)getLuaMachine(lua)); 1151 + tic_api_exit((tic_mem*)getLuaCore(lua)); 1152 1152 1153 1153 return 0; 1154 1154 } 1155 1155 1156 1156 static s32 lua_mouse(lua_State *lua) 1157 1157 { 1158 - tic_machine* machine = getLuaMachine(lua); 1158 + tic_core* core = getLuaCore(lua); 1159 1159 1160 - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; 1160 + const tic80_mouse* mouse = &core->memory.ram.input.mouse; 1161 1161 1162 1162 lua_pushinteger(lua, mouse->x); 1163 1163 lua_pushinteger(lua, mouse->y); ··· 1172 1172 1173 1173 static s32 lua_fget(lua_State* lua) 1174 1174 { 1175 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1175 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1176 1176 s32 top = lua_gettop(lua); 1177 1177 1178 1178 if(top >= 1) ··· 1194 1194 1195 1195 static s32 lua_fset(lua_State* lua) 1196 1196 { 1197 - tic_mem* tic = (tic_mem*)getLuaMachine(lua); 1197 + tic_mem* tic = (tic_mem*)getLuaCore(lua); 1198 1198 s32 top = lua_gettop(lua); 1199 1199 1200 1200 if(top >= 1) ··· 1256 1256 1257 1257 static void checkForceExit(lua_State *lua, lua_Debug *luadebug) 1258 1258 { 1259 - tic_machine* machine = getLuaMachine(lua); 1259 + tic_core* core = getLuaCore(lua); 1260 1260 1261 - tic_tick_data* tick = machine->data; 1261 + tic_tick_data* tick = core->data; 1262 1262 1263 1263 if(tick->forceExit && tick->forceExit(tick->data)) 1264 1264 luaL_error(lua, "script execution was interrupted"); 1265 1265 } 1266 1266 1267 - static void initAPI(tic_machine* machine) 1267 + static void initAPI(tic_core* core) 1268 1268 { 1269 - lua_pushlightuserdata(machine->lua, machine); 1270 - lua_setglobal(machine->lua, TicMachine); 1269 + lua_pushlightuserdata(core->lua, core); 1270 + lua_setglobal(core->lua, TicCore); 1271 1271 1272 1272 #define API_FUNC_DEF(name, ...) {lua_ ## name, #name}, 1273 1273 static const struct{lua_CFunction func; const char* name;} ApiItems[] = {TIC_API_LIST(API_FUNC_DEF)}; 1274 1274 #undef API_FUNC_DEF 1275 1275 1276 1276 for (s32 i = 0; i < COUNT_OF(ApiItems); i++) 1277 - registerLuaFunction(machine, ApiItems[i].func, ApiItems[i].name); 1277 + registerLuaFunction(core, ApiItems[i].func, ApiItems[i].name); 1278 1278 1279 - registerLuaFunction(machine, lua_dofile, "dofile"); 1280 - registerLuaFunction(machine, lua_loadfile, "loadfile"); 1279 + registerLuaFunction(core, lua_dofile, "dofile"); 1280 + registerLuaFunction(core, lua_loadfile, "loadfile"); 1281 1281 1282 - lua_sethook(machine->lua, &checkForceExit, LUA_MASKCOUNT, LUA_LOC_STACK); 1282 + lua_sethook(core->lua, &checkForceExit, LUA_MASKCOUNT, LUA_LOC_STACK); 1283 1283 } 1284 1284 1285 1285 static void closeLua(tic_mem* tic) 1286 1286 { 1287 - tic_machine* machine = (tic_machine*)tic; 1287 + tic_core* core = (tic_core*)tic; 1288 1288 1289 - if(machine->lua) 1289 + if(core->lua) 1290 1290 { 1291 - lua_close(machine->lua); 1292 - machine->lua = NULL; 1291 + lua_close(core->lua); 1292 + core->lua = NULL; 1293 1293 } 1294 1294 } 1295 1295 1296 1296 static bool initLua(tic_mem* tic, const char* code) 1297 1297 { 1298 - tic_machine* machine = (tic_machine*)tic; 1298 + tic_core* core = (tic_core*)tic; 1299 1299 1300 1300 closeLua(tic); 1301 1301 1302 - lua_State* lua = machine->lua = luaL_newstate(); 1302 + lua_State* lua = core->lua = luaL_newstate(); 1303 1303 lua_open_builtins(lua); 1304 1304 1305 - initAPI(machine); 1305 + initAPI(core); 1306 1306 1307 1307 { 1308 - lua_State* lua = machine->lua; 1308 + lua_State* lua = core->lua; 1309 1309 1310 1310 lua_settop(lua, 0); 1311 1311 1312 1312 if(luaL_loadstring(lua, code) != LUA_OK || lua_pcall(lua, 0, LUA_MULTRET, 0) != LUA_OK) 1313 1313 { 1314 - machine->data->error(machine->data->data, lua_tostring(lua, -1)); 1314 + core->data->error(core->data->data, lua_tostring(lua, -1)); 1315 1315 return false; 1316 1316 } 1317 1317 } ··· 1356 1356 1357 1357 static void callLuaTick(tic_mem* tic) 1358 1358 { 1359 - tic_machine* machine = (tic_machine*)tic; 1359 + tic_core* core = (tic_core*)tic; 1360 1360 1361 - lua_State* lua = machine->lua; 1361 + lua_State* lua = core->lua; 1362 1362 1363 1363 if(lua) 1364 1364 { ··· 1366 1366 if(lua_isfunction(lua, -1)) 1367 1367 { 1368 1368 if(docall(lua, 0, 0) != LUA_OK) 1369 - machine->data->error(machine->data->data, lua_tostring(lua, -1)); 1369 + core->data->error(core->data->data, lua_tostring(lua, -1)); 1370 1370 } 1371 1371 else 1372 1372 { 1373 1373 lua_pop(lua, 1); 1374 - machine->data->error(machine->data->data, "'function TIC()...' isn't found :("); 1374 + core->data->error(core->data->data, "'function TIC()...' isn't found :("); 1375 1375 } 1376 1376 } 1377 1377 } 1378 1378 1379 1379 static void callLuaScanlineName(tic_mem* tic, s32 row, void* data, const char* name) 1380 1380 { 1381 - tic_machine* machine = (tic_machine*)tic; 1382 - lua_State* lua = machine->lua; 1381 + tic_core* core = (tic_core*)tic; 1382 + lua_State* lua = core->lua; 1383 1383 1384 1384 if (lua) 1385 1385 { ··· 1388 1388 { 1389 1389 lua_pushinteger(lua, row); 1390 1390 if(docall(lua, 1, 0) != LUA_OK) 1391 - machine->data->error(machine->data->data, lua_tostring(lua, -1)); 1391 + core->data->error(core->data->data, lua_tostring(lua, -1)); 1392 1392 } 1393 1393 else lua_pop(lua, 1); 1394 1394 } ··· 1404 1404 1405 1405 static void callLuaOverline(tic_mem* tic, void* data) 1406 1406 { 1407 - tic_machine* machine = (tic_machine*)tic; 1408 - lua_State* lua = machine->lua; 1407 + tic_core* core = (tic_core*)tic; 1408 + lua_State* lua = core->lua; 1409 1409 1410 1410 if (lua) 1411 1411 { ··· 1415 1415 if(lua_isfunction(lua, -1)) 1416 1416 { 1417 1417 if(docall(lua, 0, 0) != LUA_OK) 1418 - machine->data->error(machine->data->data, lua_tostring(lua, -1)); 1418 + core->data->error(core->data->data, lua_tostring(lua, -1)); 1419 1419 } 1420 1420 else lua_pop(lua, 1); 1421 1421 } ··· 1493 1493 } 1494 1494 1495 1495 static void evalLua(tic_mem* tic, const char* code) { 1496 - tic_machine* machine = (tic_machine*)tic; 1497 - lua_State* lua = machine->lua; 1496 + tic_core* core = (tic_core*)tic; 1497 + lua_State* lua = core->lua; 1498 1498 1499 1499 if (!lua) return; 1500 1500 ··· 1502 1502 1503 1503 if(luaL_loadstring(lua, code) != LUA_OK || lua_pcall(lua, 0, LUA_MULTRET, 0) != LUA_OK) 1504 1504 { 1505 - machine->data->error(machine->data->data, lua_tostring(lua, -1)); 1505 + core->data->error(core->data->data, lua_tostring(lua, -1)); 1506 1506 } 1507 1507 } 1508 1508 ··· 1566 1566 1567 1567 static bool initMoonscript(tic_mem* tic, const char* code) 1568 1568 { 1569 - tic_machine* machine = (tic_machine*)tic; 1569 + tic_core* core = (tic_core*)tic; 1570 1570 closeLua(tic); 1571 1571 1572 - lua_State* lua = machine->lua = luaL_newstate(); 1572 + lua_State* lua = core->lua = luaL_newstate(); 1573 1573 lua_open_builtins(lua); 1574 1574 1575 1575 luaopen_lpeg(lua); 1576 1576 setloaded(lua, "lpeg"); 1577 1577 1578 - initAPI(machine); 1578 + initAPI(core); 1579 1579 1580 1580 { 1581 - lua_State* moon = machine->lua; 1581 + lua_State* moon = core->lua; 1582 1582 1583 1583 lua_settop(moon, 0); 1584 1584 1585 1585 if (luaL_loadbuffer(moon, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") != LUA_OK) 1586 1586 { 1587 - machine->data->error(machine->data->data, "failed to load moonscript.lua"); 1587 + core->data->error(core->data->data, "failed to load moonscript.lua"); 1588 1588 return false; 1589 1589 } 1590 1590 ··· 1592 1592 1593 1593 if (luaL_loadbuffer(moon, execute_moonscript_src, strlen(execute_moonscript_src), "execute_moonscript") != LUA_OK) 1594 1594 { 1595 - machine->data->error(machine->data->data, "failed to load moonscript compiler"); 1595 + core->data->error(core->data->data, "failed to load moonscript compiler"); 1596 1596 return false; 1597 1597 } 1598 1598 ··· 1603 1603 1604 1604 if (msg) 1605 1605 { 1606 - machine->data->error(machine->data->data, msg); 1606 + core->data->error(core->data->data, msg); 1607 1607 return false; 1608 1608 } 1609 1609 } ··· 1717 1717 1718 1718 static bool initFennel(tic_mem* tic, const char* code) 1719 1719 { 1720 - tic_machine* machine = (tic_machine*)tic; 1720 + tic_core* core = (tic_core*)tic; 1721 1721 closeLua(tic); 1722 1722 1723 - lua_State* lua = machine->lua = luaL_newstate(); 1723 + lua_State* lua = core->lua = luaL_newstate(); 1724 1724 lua_open_builtins(lua); 1725 1725 1726 - initAPI(machine); 1726 + initAPI(core); 1727 1727 1728 1728 { 1729 - lua_State* fennel = machine->lua; 1729 + lua_State* fennel = core->lua; 1730 1730 1731 1731 lua_settop(fennel, 0); 1732 1732 1733 1733 if (luaL_loadbuffer(fennel, (const char *)loadfennel_lua, 1734 1734 loadfennel_lua_len, "fennel.lua") != LUA_OK) 1735 1735 { 1736 - machine->data->error(machine->data->data, "failed to load fennel compiler"); 1736 + core->data->error(core->data->data, "failed to load fennel compiler"); 1737 1737 return false; 1738 1738 } 1739 1739 ··· 1741 1741 1742 1742 if (luaL_loadbuffer(fennel, execute_fennel_src, strlen(execute_fennel_src), "execute_fennel") != LUA_OK) 1743 1743 { 1744 - machine->data->error(machine->data->data, "failed to load fennel compiler"); 1744 + core->data->error(core->data->data, "failed to load fennel compiler"); 1745 1745 return false; 1746 1746 } 1747 1747 ··· 1751 1751 1752 1752 if (err) 1753 1753 { 1754 - machine->data->error(machine->data->data, err); 1754 + core->data->error(core->data->data, err); 1755 1755 return false; 1756 1756 } 1757 1757 } ··· 1828 1828 } 1829 1829 1830 1830 static void evalFennel(tic_mem* tic, const char* code) { 1831 - tic_machine* machine = (tic_machine*)tic; 1832 - lua_State* fennel = machine->lua; 1831 + tic_core* core = (tic_core*)tic; 1832 + lua_State* fennel = core->lua; 1833 1833 1834 1834 lua_settop(fennel, 0); 1835 1835 1836 1836 if (luaL_loadbuffer(fennel, execute_fennel_src, strlen(execute_fennel_src), "execute_fennel") != LUA_OK) 1837 1837 { 1838 - machine->data->error(machine->data->data, "failed to load fennel compiler"); 1838 + core->data->error(core->data->data, "failed to load fennel compiler"); 1839 1839 } 1840 1840 1841 1841 lua_pushstring(fennel, code); ··· 1844 1844 1845 1845 if (err) 1846 1846 { 1847 - machine->data->error(machine->data->data, err); 1847 + core->data->error(core->data->data, err); 1848 1848 } 1849 1849 } 1850 1850
+109 -109
src/api/squirrel.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "core/machine.h" 23 + #include "core/core.h" 24 24 25 25 #if defined(TIC_BUILD_WITH_SQUIRREL) 26 26 ··· 36 36 #include <sqstdblob.h> 37 37 #include <ctype.h> 38 38 39 - static const char TicMachine[] = "_TIC80"; 39 + static const char TicCore[] = "_TIC80"; 40 40 41 41 42 42 // !TODO: get rid of this wrap ··· 53 53 return 0; 54 54 } 55 55 56 - static void registerSquirrelFunction(tic_machine* machine, SQFUNCTION func, const char *name) 56 + static void registerSquirrelFunction(tic_core* core, SQFUNCTION func, const char *name) 57 57 { 58 - sq_pushroottable(machine->squirrel); 59 - sq_pushstring(machine->squirrel, name, -1); 60 - sq_newclosure(machine->squirrel, func, 0); 61 - sq_newslot(machine->squirrel, -3, SQTrue); 62 - sq_poptop(machine->squirrel); // remove root table. 58 + sq_pushroottable(core->squirrel); 59 + sq_pushstring(core->squirrel, name, -1); 60 + sq_newclosure(core->squirrel, func, 0); 61 + sq_newslot(core->squirrel, -3, SQTrue); 62 + sq_poptop(core->squirrel); // remove root table. 63 63 } 64 64 65 - static tic_machine* getSquirrelMachine(HSQUIRRELVM vm) 65 + static tic_core* getSquirrelCore(HSQUIRRELVM vm) 66 66 { 67 67 #if USE_FOREIGN_POINTER 68 - return (tic_machine*)sq_getforeignpointer(vm); 68 + return (tic_core*)sq_getforeignpointer(vm); 69 69 #else 70 70 sq_pushregistrytable(vm); 71 - sq_pushstring(vm, TicMachine, -1); 71 + sq_pushstring(vm, TicCore, -1); 72 72 if (SQ_FAILED(sq_get(vm, -2))) 73 73 { 74 - fprintf(stderr, "FATAL ERROR: TicMachine not found!\n"); 74 + fprintf(stderr, "FATAL ERROR: TicCore not found!\n"); 75 75 abort(); 76 76 } 77 77 SQUserPointer ptr; 78 78 if (SQ_FAILED(sq_getuserpointer(vm, -1, &ptr))) 79 79 { 80 - fprintf(stderr, "FATAL ERROR: Cannot get user pointer for TicMachine!\n"); 80 + fprintf(stderr, "FATAL ERROR: Cannot get user pointer for TicCore!\n"); 81 81 abort(); 82 82 } 83 - tic_machine* machine = (tic_machine*)ptr; 83 + tic_core* core = (tic_core*)ptr; 84 84 sq_pop(vm, 2); // user pointer and registry table. 85 - return machine; 85 + return core; 86 86 #endif 87 87 } 88 88 89 89 void squirrel_compilerError(HSQUIRRELVM vm, const SQChar* desc, const SQChar* source, 90 90 SQInteger line, SQInteger column) 91 91 { 92 - tic_machine* machine = getSquirrelMachine(vm); 92 + tic_core* core = getSquirrelCore(vm); 93 93 char buffer[1024]; 94 94 snprintf(buffer, 1023, "%.40s line %.6d column %.6d: %s\n", source, (int)line, (int)column, desc); 95 95 96 - if (machine->data) 97 - machine->data->error(machine->data->data, buffer); 96 + if (core->data) 97 + core->data->error(core->data->data, buffer); 98 98 } 99 99 100 100 static SQInteger squirrel_errorHandler(HSQUIRRELVM vm) 101 101 { 102 - tic_machine* machine = getSquirrelMachine(vm); 102 + tic_core* core = getSquirrelCore(vm); 103 103 104 104 SQStackInfos si; 105 105 SQInteger level = 0; ··· 108 108 char buffer[100]; 109 109 snprintf(buffer, 99, "%.40s %.40s %.6d\n", si.funcname, si.source, (int)si.line); 110 110 111 - if (machine->data) 112 - machine->data->error(machine->data->data, buffer); 111 + if (core->data) 112 + core->data->error(core->data->data, buffer); 113 113 ++level; 114 114 } 115 115 ··· 119 119 120 120 static SQInteger squirrel_peek(HSQUIRRELVM vm) 121 121 { 122 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 122 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 123 123 124 124 // check number of args 125 125 if (sq_gettop(vm) != 2) ··· 132 132 133 133 static SQInteger squirrel_poke(HSQUIRRELVM vm) 134 134 { 135 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 135 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 136 136 137 137 if (sq_gettop(vm) != 3) 138 138 return sq_throwerror( vm, "invalid parameters, poke(address,value)" ); ··· 147 147 148 148 static SQInteger squirrel_peek4(HSQUIRRELVM vm) 149 149 { 150 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 150 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 151 151 152 152 // check number of args 153 153 if (sq_gettop(vm) != 2) ··· 160 160 161 161 static SQInteger squirrel_poke4(HSQUIRRELVM vm) 162 162 { 163 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 163 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 164 164 165 165 if (sq_gettop(vm) != 3) 166 166 return sq_throwerror( vm, "invalid parameters, poke4(address,value)" ); ··· 177 177 { 178 178 SQInteger top = sq_gettop(vm); 179 179 180 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 180 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 181 181 182 182 tic_api_cls(tic, top == 2 ? getSquirrelNumber(vm, 2) : 0); 183 183 ··· 193 193 s32 x = getSquirrelNumber(vm, 2); 194 194 s32 y = getSquirrelNumber(vm, 3); 195 195 196 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 196 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 197 197 198 198 if(top >= 4) 199 199 { ··· 226 226 s32 y1 = getSquirrelNumber(vm, 5); 227 227 s32 color = getSquirrelNumber(vm, 6); 228 228 229 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 229 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 230 230 231 231 tic_api_line(tic, x0, y0, x1, y1, color); 232 232 } ··· 247 247 s32 h = getSquirrelNumber(vm, 5); 248 248 s32 color = getSquirrelNumber(vm, 6); 249 249 250 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 250 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 251 251 252 252 tic_api_rect(tic, x, y, w, h, color); 253 253 } ··· 268 268 s32 h = getSquirrelNumber(vm, 5); 269 269 s32 color = getSquirrelNumber(vm, 6); 270 270 271 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 271 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 272 272 273 273 tic_api_rectb(tic, x, y, w, h, color); 274 274 } ··· 290 290 s32 y = getSquirrelNumber(vm, 3); 291 291 s32 color = getSquirrelNumber(vm, 5); 292 292 293 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 293 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 294 294 295 295 tic_api_circ(tic, x, y, radius, color); 296 296 } ··· 312 312 s32 y = getSquirrelNumber(vm, 3); 313 313 s32 color = getSquirrelNumber(vm, 5); 314 314 315 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 315 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 316 316 317 317 tic_api_circb(tic, x, y, radius, color); 318 318 } ··· 334 334 335 335 s32 color = getSquirrelNumber(vm, 8); 336 336 337 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 337 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 338 338 339 339 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); 340 340 } ··· 358 358 pt[i] = (float)f; 359 359 } 360 360 361 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 361 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 362 362 static u8 colors[TIC_PALETTE_SIZE]; 363 363 s32 count = 0; 364 364 bool use_map = false; ··· 416 416 417 417 if(top == 1) 418 418 { 419 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 419 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 420 420 421 421 tic_api_clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); 422 422 } ··· 427 427 s32 w = getSquirrelNumber(vm, 4); 428 428 s32 h = getSquirrelNumber(vm, 5); 429 429 430 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 430 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 431 431 432 - tic_api_clip((tic_mem*)getSquirrelMachine(vm), x, y, w, h); 432 + tic_api_clip((tic_mem*)getSquirrelCore(vm), x, y, w, h); 433 433 } 434 434 else return sq_throwerror(vm, "invalid parameters, use clip(x,y,w,h) or clip()\n"); 435 435 ··· 438 438 439 439 static SQInteger squirrel_btnp(HSQUIRRELVM vm) 440 440 { 441 - tic_machine* machine = getSquirrelMachine(vm); 442 - tic_mem* tic = (tic_mem*)machine; 441 + tic_core* core = getSquirrelCore(vm); 442 + tic_mem* tic = (tic_mem*)core; 443 443 444 444 SQInteger top = sq_gettop(vm); 445 445 ··· 471 471 472 472 static SQInteger squirrel_btn(HSQUIRRELVM vm) 473 473 { 474 - tic_machine* machine = getSquirrelMachine(vm); 474 + tic_core* core = getSquirrelCore(vm); 475 475 476 476 SQInteger top = sq_gettop(vm); 477 477 478 478 if (top == 1) 479 479 { 480 - sq_pushinteger(vm, machine->memory.ram.input.gamepads.data); 480 + sq_pushinteger(vm, core->memory.ram.input.gamepads.data); 481 481 } 482 482 else if (top == 2) 483 483 { 484 484 u32 index = getSquirrelNumber(vm, 2) & 0x1f; 485 - bool pressed = (machine->memory.ram.input.gamepads.data & (1 << index)) != 0; 485 + bool pressed = (core->memory.ram.input.gamepads.data & (1 << index)) != 0; 486 486 sq_pushbool(vm, pressed ? SQTrue : SQFalse); 487 487 } 488 488 else ··· 568 568 } 569 569 } 570 570 571 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 571 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 572 572 573 573 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); 574 574 ··· 584 584 s32 x = getSquirrelNumber(vm, 2); 585 585 s32 y = getSquirrelNumber(vm, 3); 586 586 587 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 587 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 588 588 589 589 u8 value = tic_api_mget(tic, x, y); 590 590 sq_pushinteger(vm, value); ··· 605 605 s32 y = getSquirrelNumber(vm, 3); 606 606 u8 val = getSquirrelNumber(vm, 4); 607 607 608 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 608 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 609 609 610 610 tic_api_mset(tic, x, y, val); 611 611 } ··· 729 729 sq_getstackobj(vm, 10, &data.reg); 730 730 sq_addref(vm, &data.reg); 731 731 732 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 732 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 733 733 734 734 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); 735 735 ··· 745 745 } 746 746 } 747 747 748 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 748 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 749 749 750 - tic_api_map((tic_mem*)getSquirrelMachine(vm), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); 750 + tic_api_map((tic_mem*)getSquirrelCore(vm), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); 751 751 752 752 return 0; 753 753 } ··· 755 755 static SQInteger squirrel_music(HSQUIRRELVM vm) 756 756 { 757 757 SQInteger top = sq_gettop(vm); 758 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 758 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 759 759 760 760 if(top == 1) tic_api_music(tic, -1, 0, 0, false, false); 761 761 else if(top >= 2) ··· 804 804 805 805 if(top >= 2) 806 806 { 807 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 807 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 808 808 809 809 s32 note = -1; 810 810 s32 octave = -1; ··· 882 882 883 883 static SQInteger squirrel_sync(HSQUIRRELVM vm) 884 884 { 885 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 885 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 886 886 887 887 bool toCart = false; 888 888 u32 mask = 0; ··· 915 915 916 916 static SQInteger squirrel_reset(HSQUIRRELVM vm) 917 917 { 918 - tic_machine* machine = getSquirrelMachine(vm); 918 + tic_core* core = getSquirrelCore(vm); 919 919 920 - machine->state.initialized = false; 920 + core->state.initialized = false; 921 921 922 922 return 0; 923 923 } 924 924 925 925 static SQInteger squirrel_key(HSQUIRRELVM vm) 926 926 { 927 - tic_machine* machine = getSquirrelMachine(vm); 928 - tic_mem* tic = &machine->memory; 927 + tic_core* core = getSquirrelCore(vm); 928 + tic_mem* tic = &core->memory; 929 929 930 930 SQInteger top = sq_gettop(vm); 931 931 ··· 954 954 955 955 static SQInteger squirrel_keyp(HSQUIRRELVM vm) 956 956 { 957 - tic_machine* machine = getSquirrelMachine(vm); 958 - tic_mem* tic = &machine->memory; 957 + tic_core* core = getSquirrelCore(vm); 958 + tic_mem* tic = &core->memory; 959 959 960 960 SQInteger top = sq_gettop(vm); 961 961 ··· 1004 1004 s32 src = getSquirrelNumber(vm, 3); 1005 1005 s32 size = getSquirrelNumber(vm, 4); 1006 1006 1007 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1007 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1008 1008 tic_api_memcpy(tic, dest, src, size); 1009 1009 return 0; 1010 1010 } ··· 1022 1022 u8 value = getSquirrelNumber(vm, 3); 1023 1023 s32 size = getSquirrelNumber(vm, 4); 1024 1024 1025 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1025 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1026 1026 tic_api_memset(tic, dest, value, size); 1027 1027 return 0; 1028 1028 } ··· 1044 1044 1045 1045 static SQInteger squirrel_font(HSQUIRRELVM vm) 1046 1046 { 1047 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1047 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1048 1048 SQInteger top = sq_gettop(vm); 1049 1049 1050 1050 if(top >= 2) ··· 1117 1117 1118 1118 if(top >= 2) 1119 1119 { 1120 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1120 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1121 1121 1122 1122 s32 x = 0; 1123 1123 s32 y = 0; ··· 1177 1177 static SQInteger squirrel_trace(HSQUIRRELVM vm) 1178 1178 { 1179 1179 SQInteger top = sq_gettop(vm); 1180 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1180 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1181 1181 1182 1182 if(top >= 2) 1183 1183 { ··· 1198 1198 static SQInteger squirrel_pmem(HSQUIRRELVM vm) 1199 1199 { 1200 1200 SQInteger top = sq_gettop(vm); 1201 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1201 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1202 1202 1203 1203 if(top >= 2) 1204 1204 { ··· 1228 1228 1229 1229 static SQInteger squirrel_time(HSQUIRRELVM vm) 1230 1230 { 1231 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1231 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1232 1232 1233 1233 sq_pushfloat(vm, (SQFloat)(tic_api_time(tic))); 1234 1234 ··· 1237 1237 1238 1238 static SQInteger squirrel_tstamp(HSQUIRRELVM vm) 1239 1239 { 1240 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1240 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1241 1241 1242 1242 sq_pushinteger(vm, (SQFloat)(tic_api_tstamp(tic))); 1243 1243 ··· 1246 1246 1247 1247 static SQInteger squirrel_exit(HSQUIRRELVM vm) 1248 1248 { 1249 - tic_api_exit((tic_mem*)getSquirrelMachine(vm)); 1249 + tic_api_exit((tic_mem*)getSquirrelCore(vm)); 1250 1250 1251 1251 return 0; 1252 1252 } 1253 1253 1254 1254 static SQInteger squirrel_mouse(HSQUIRRELVM vm) 1255 1255 { 1256 - tic_machine* machine = getSquirrelMachine(vm); 1256 + tic_core* core = getSquirrelCore(vm); 1257 1257 1258 - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; 1258 + const tic80_mouse* mouse = &core->memory.ram.input.mouse; 1259 1259 1260 1260 sq_newarray(vm, 7); 1261 1261 sq_pushinteger(vm, mouse->x); ··· 1278 1278 1279 1279 static SQInteger squirrel_fget(HSQUIRRELVM vm) 1280 1280 { 1281 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1281 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1282 1282 1283 1283 SQInteger top = sq_gettop(vm); 1284 1284 ··· 1301 1301 1302 1302 static SQInteger squirrel_fset(HSQUIRRELVM vm) 1303 1303 { 1304 - tic_mem* tic = (tic_mem*)getSquirrelMachine(vm); 1304 + tic_mem* tic = (tic_mem*)getSquirrelCore(vm); 1305 1305 1306 1306 SQInteger top = sq_gettop(vm); 1307 1307 ··· 1350 1350 1351 1351 static void checkForceExit(HSQUIRRELVM vm, SQInteger type, const SQChar* sourceName, SQInteger line, const SQChar* functionName) 1352 1352 { 1353 - tic_machine* machine = getSquirrelMachine(vm); 1354 - tic_tick_data* tick = machine->data; 1353 + tic_core* core = getSquirrelCore(vm); 1354 + tic_tick_data* tick = core->data; 1355 1355 1356 1356 if(tick && tick->forceExit && tick->forceExit(tick->data)) 1357 1357 sq_throwerror(vm, "script execution was interrupted"); 1358 1358 } 1359 1359 1360 - static void initAPI(tic_machine* machine) 1360 + static void initAPI(tic_core* core) 1361 1361 { 1362 - HSQUIRRELVM vm = machine->squirrel; 1362 + HSQUIRRELVM vm = core->squirrel; 1363 1363 1364 1364 sq_setcompilererrorhandler(vm, squirrel_compilerError); 1365 1365 1366 1366 sq_pushregistrytable(vm); 1367 - sq_pushstring(vm, TicMachine, -1); 1368 - sq_pushuserpointer(machine->squirrel, machine); 1367 + sq_pushstring(vm, TicCore, -1); 1368 + sq_pushuserpointer(core->squirrel, core); 1369 1369 sq_newslot(vm, -3, SQTrue); 1370 1370 sq_poptop(vm); 1371 1371 1372 1372 #if USE_FOREIGN_POINTER 1373 - sq_setforeignptr(vm, machine); 1373 + sq_setforeignptr(vm, core); 1374 1374 #endif 1375 1375 1376 1376 #define API_FUNC_DEF(name, ...) {squirrel_ ## name, #name}, ··· 1378 1378 #undef API_FUNC_DEF 1379 1379 1380 1380 for (s32 i = 0; i < COUNT_OF(ApiItems); i++) 1381 - registerSquirrelFunction(machine, ApiItems[i].func, ApiItems[i].name); 1381 + registerSquirrelFunction(core, ApiItems[i].func, ApiItems[i].name); 1382 1382 1383 - registerSquirrelFunction(machine, squirrel_dofile, "dofile"); 1384 - registerSquirrelFunction(machine, squirrel_loadfile, "loadfile"); 1383 + registerSquirrelFunction(core, squirrel_dofile, "dofile"); 1384 + registerSquirrelFunction(core, squirrel_loadfile, "loadfile"); 1385 1385 1386 1386 #if CHECK_FORCE_EXIT 1387 1387 sq_setnativedebughook(vm, checkForceExit); ··· 1392 1392 1393 1393 static void closeSquirrel(tic_mem* tic) 1394 1394 { 1395 - tic_machine* machine = (tic_machine*)tic; 1395 + tic_core* core = (tic_core*)tic; 1396 1396 1397 - if(machine->squirrel) 1397 + if(core->squirrel) 1398 1398 { 1399 - sq_close(machine->squirrel); 1400 - machine->squirrel = NULL; 1399 + sq_close(core->squirrel); 1400 + core->squirrel = NULL; 1401 1401 } 1402 1402 } 1403 1403 1404 1404 static bool initSquirrel(tic_mem* tic, const char* code) 1405 1405 { 1406 - tic_machine* machine = (tic_machine*)tic; 1406 + tic_core* core = (tic_core*)tic; 1407 1407 1408 1408 closeSquirrel(tic); 1409 1409 1410 - HSQUIRRELVM vm = machine->squirrel = sq_open(100); 1410 + HSQUIRRELVM vm = core->squirrel = sq_open(100); 1411 1411 squirrel_open_builtins(vm); 1412 1412 1413 1413 sq_newclosure(vm, squirrel_errorHandler, 0); 1414 1414 sq_seterrorhandler(vm); 1415 1415 1416 - initAPI(machine); 1416 + initAPI(core); 1417 1417 1418 1418 { 1419 - HSQUIRRELVM vm = machine->squirrel; 1419 + HSQUIRRELVM vm = core->squirrel; 1420 1420 1421 1421 sq_settop(vm, 0); 1422 1422 ··· 1429 1429 const SQChar* errorString = "unknown error"; 1430 1430 sq_getstring(vm, -1, &errorString); 1431 1431 1432 - if (machine->data) 1433 - machine->data->error(machine->data->data, errorString); 1432 + if (core->data) 1433 + core->data->error(core->data->data, errorString); 1434 1434 1435 1435 sq_pop(vm, 2); // error and error string 1436 1436 ··· 1443 1443 1444 1444 static void callSquirrelTick(tic_mem* tic) 1445 1445 { 1446 - tic_machine* machine = (tic_machine*)tic; 1446 + tic_core* core = (tic_core*)tic; 1447 1447 1448 - HSQUIRRELVM vm = machine->squirrel; 1448 + HSQUIRRELVM vm = core->squirrel; 1449 1449 1450 1450 if(vm) 1451 1451 { ··· 1462 1462 const SQChar* errorString = "unknown error"; 1463 1463 sq_getstring(vm, -1, &errorString); 1464 1464 1465 - if (machine->data) 1466 - machine->data->error(machine->data->data, errorString); 1465 + if (core->data) 1466 + core->data->error(core->data->data, errorString); 1467 1467 sq_pop(vm, 3); // remove string, error and root table. 1468 1468 } 1469 1469 } 1470 1470 else 1471 1471 { 1472 1472 sq_pop(vm, 1); 1473 - if (machine->data) 1474 - machine->data->error(machine->data->data, "'function TIC()...' isn't found :("); 1473 + if (core->data) 1474 + core->data->error(core->data->data, "'function TIC()...' isn't found :("); 1475 1475 } 1476 1476 } 1477 1477 } 1478 1478 1479 1479 static void callSquirrelScanlineName(tic_mem* tic, s32 row, void* data, const char* name) 1480 1480 { 1481 - tic_machine* machine = (tic_machine*)tic; 1482 - HSQUIRRELVM vm = machine->squirrel; 1481 + tic_core* core = (tic_core*)tic; 1482 + HSQUIRRELVM vm = core->squirrel; 1483 1483 1484 1484 if (vm) 1485 1485 { ··· 1497 1497 1498 1498 const SQChar* errorString = "unknown error"; 1499 1499 sq_getstring(vm, -1, &errorString); 1500 - if (machine->data) 1501 - machine->data->error(machine->data->data, errorString); 1500 + if (core->data) 1501 + core->data->error(core->data->data, errorString); 1502 1502 sq_pop(vm, 3); // error string, error and root table 1503 1503 } 1504 1504 } ··· 1516 1516 1517 1517 static void callSquirrelOverline(tic_mem* tic, void* data) 1518 1518 { 1519 - tic_machine* machine = (tic_machine*)tic; 1520 - HSQUIRRELVM vm = machine->squirrel; 1519 + tic_core* core = (tic_core*)tic; 1520 + HSQUIRRELVM vm = core->squirrel; 1521 1521 1522 1522 if (vm) 1523 1523 { ··· 1535 1535 sq_tostring(vm, -1); 1536 1536 const SQChar* errorString = "unknown error"; 1537 1537 sq_getstring(vm, -1, &errorString); 1538 - if (machine->data) 1539 - machine->data->error(machine->data->data, errorString); 1538 + if (core->data) 1539 + core->data->error(core->data->data, errorString); 1540 1540 sq_pop(vm, 3); 1541 1541 } 1542 1542 } ··· 1618 1618 } 1619 1619 1620 1620 void evalSquirrel(tic_mem* tic, const char* code) { 1621 - tic_machine* machine = (tic_machine*)tic; 1622 - HSQUIRRELVM vm = machine->squirrel; 1621 + tic_core* core = (tic_core*)tic; 1622 + HSQUIRRELVM vm = core->squirrel; 1623 1623 1624 1624 // make sure that the Squirrel interpreter is initialized. 1625 1625 if (vm == NULL) 1626 1626 { 1627 1627 if (!initSquirrel(tic, "")) 1628 1628 return; 1629 - vm = machine->squirrel; 1629 + vm = core->squirrel; 1630 1630 } 1631 1631 1632 1632 sq_settop(vm, 0); ··· 1639 1639 sq_tostring(vm, -1); 1640 1640 const SQChar* errorString = "unknown error"; 1641 1641 sq_getstring(vm, -1, &errorString); 1642 - if (machine->data) 1643 - machine->data->error(machine->data->data, errorString); 1642 + if (core->data) 1643 + core->data->error(core->data->data, errorString); 1644 1644 } 1645 1645 1646 1646 sq_settop(vm, 0);
+83 -83
src/api/wren.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "core/machine.h" 23 + #include "core/core.h" 24 24 25 25 #if defined(TIC_BUILD_WITH_WREN) 26 26 ··· 196 196 197 197 static void closeWren(tic_mem* tic) 198 198 { 199 - tic_machine* machine = (tic_machine*)tic; 200 - if(machine->wren) 199 + tic_core* core = (tic_core*)tic; 200 + if(core->wren) 201 201 { 202 202 // release handles 203 203 if (loaded) 204 204 { 205 - wrenReleaseHandle(machine->wren, new_handle); 206 - wrenReleaseHandle(machine->wren, update_handle); 207 - wrenReleaseHandle(machine->wren, scanline_handle); 208 - wrenReleaseHandle(machine->wren, overline_handle); 205 + wrenReleaseHandle(core->wren, new_handle); 206 + wrenReleaseHandle(core->wren, update_handle); 207 + wrenReleaseHandle(core->wren, scanline_handle); 208 + wrenReleaseHandle(core->wren, overline_handle); 209 209 if (game_class != NULL) 210 210 { 211 - wrenReleaseHandle(machine->wren, game_class); 211 + wrenReleaseHandle(core->wren, game_class); 212 212 } 213 213 } 214 214 215 - wrenFreeVM(machine->wren); 216 - machine->wren = NULL; 215 + wrenFreeVM(core->wren); 216 + core->wren = NULL; 217 217 218 218 } 219 219 loaded = false; 220 220 } 221 221 222 - static tic_machine* getWrenMachine(WrenVM* vm) 222 + static tic_core* getWrenCore(WrenVM* vm) 223 223 { 224 - tic_machine* machine = wrenGetUserData(vm); 224 + tic_core* core = wrenGetUserData(vm); 225 225 226 - return machine; 226 + return core; 227 227 } 228 228 229 229 static void wren_map_width(WrenVM* vm) ··· 246 246 return; 247 247 } 248 248 249 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 249 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 250 250 wrenSetSlotDouble(vm, 0, *(tic->ram.map.data + index)); 251 251 } 252 252 ··· 257 257 258 258 static void wren_btn(WrenVM* vm) 259 259 { 260 - tic_machine* machine = getWrenMachine(vm); 260 + tic_core* core = getWrenCore(vm); 261 261 262 262 s32 top = wrenGetSlotCount(vm); 263 263 264 264 if (top == 1) 265 265 { 266 - wrenSetSlotBool(vm, 0, machine->memory.ram.input.gamepads.data); 266 + wrenSetSlotBool(vm, 0, core->memory.ram.input.gamepads.data); 267 267 } 268 268 else if (top == 2) 269 269 { 270 270 s32 index = getWrenNumber(vm, 1) & 0xf; 271 - wrenSetSlotBool(vm, 0, machine->memory.ram.input.gamepads.data & (1 << index)); 271 + wrenSetSlotBool(vm, 0, core->memory.ram.input.gamepads.data & (1 << index)); 272 272 } 273 273 274 274 } 275 275 276 276 static void wren_btnp(WrenVM* vm) 277 277 { 278 - tic_machine* machine = getWrenMachine(vm); 279 - tic_mem* tic = (tic_mem*)machine; 278 + tic_core* core = getWrenCore(vm); 279 + tic_mem* tic = (tic_mem*)core; 280 280 281 281 s32 top = wrenGetSlotCount(vm); 282 282 ··· 302 302 303 303 static void wren_key(WrenVM* vm) 304 304 { 305 - tic_machine* machine = getWrenMachine(vm); 306 - tic_mem* tic = &machine->memory; 305 + tic_core* core = getWrenCore(vm); 306 + tic_mem* tic = &core->memory; 307 307 308 308 s32 top = wrenGetSlotCount(vm); 309 309 ··· 327 327 328 328 static void wren_keyp(WrenVM* vm) 329 329 { 330 - tic_machine* machine = getWrenMachine(vm); 331 - tic_mem* tic = &machine->memory; 330 + tic_core* core = getWrenCore(vm); 331 + tic_mem* tic = &core->memory; 332 332 333 333 s32 top = wrenGetSlotCount(vm); 334 334 ··· 364 364 365 365 static void wren_mouse(WrenVM* vm) 366 366 { 367 - tic_machine* machine = getWrenMachine(vm); 367 + tic_core* core = getWrenCore(vm); 368 368 369 - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; 369 + const tic80_mouse* mouse = &core->memory.ram.input.mouse; 370 370 371 371 wrenEnsureSlots(vm, 6); 372 372 wrenSetSlotNewList(vm, 0); ··· 388 388 389 389 static void wren_print(WrenVM* vm) 390 390 { 391 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 391 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 392 392 393 393 const char* text = wrenGetSlotString(vm, 1); 394 394 ··· 416 416 417 417 static void wren_font(WrenVM* vm) 418 418 { 419 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 419 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 420 420 s32 top = wrenGetSlotCount(vm); 421 421 422 422 if(top > 1) ··· 481 481 482 482 static void wren_trace(WrenVM* vm) 483 483 { 484 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 484 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 485 485 486 486 const char* text = wrenGetSlotString(vm, 1); 487 487 u8 color = (u8)getWrenNumber(vm, 2); ··· 563 563 } 564 564 } 565 565 566 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 566 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 567 567 568 568 tic_api_spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); 569 569 } ··· 607 607 s32 flip = getWrenNumber(vm, 6); 608 608 s32 rotate = getWrenNumber(vm, 7); 609 609 610 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 610 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 611 611 612 612 tic_api_spr(tic, index, x, y, 1, 1, colors, count, scale, flip, rotate); 613 613 } ··· 676 676 } 677 677 } 678 678 679 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 679 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 680 680 681 681 tic_api_map(tic, x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); 682 682 } ··· 687 687 s32 y = getWrenNumber(vm, 2); 688 688 u8 value = getWrenNumber(vm, 3); 689 689 690 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 690 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 691 691 692 692 tic_api_mset(tic, x, y, value); 693 693 } ··· 697 697 s32 x = getWrenNumber(vm, 1); 698 698 s32 y = getWrenNumber(vm, 2); 699 699 700 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 700 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 701 701 702 702 u8 value = tic_api_mget(tic, x, y); 703 703 wrenSetSlotDouble(vm, 0, value); ··· 714 714 pt[i] = (float)getWrenNumber(vm, i + 1); 715 715 } 716 716 717 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 717 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 718 718 static u8 colors[TIC_PALETTE_SIZE]; 719 719 s32 count = 0; 720 720 bool use_map = false; ··· 767 767 s32 x = getWrenNumber(vm, 1); 768 768 s32 y = getWrenNumber(vm, 2); 769 769 770 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 770 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 771 771 772 772 if(top > 3) 773 773 { ··· 788 788 s32 y1 = getWrenNumber(vm, 4); 789 789 s32 color = getWrenNumber(vm, 5); 790 790 791 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 791 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 792 792 793 793 tic_api_line(tic, x0, y0, x1, y1, color); 794 794 } ··· 805 805 s32 y = getWrenNumber(vm, 2); 806 806 s32 color = getWrenNumber(vm, 4); 807 807 808 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 808 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 809 809 810 810 tic_api_circ(tic, x, y, radius, color); 811 811 } ··· 822 822 s32 y = getWrenNumber(vm, 2); 823 823 s32 color = getWrenNumber(vm, 4); 824 824 825 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 825 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 826 826 827 827 tic_api_circb(tic, x, y, radius, color); 828 828 } ··· 835 835 s32 h = getWrenNumber(vm, 4); 836 836 s32 color = getWrenNumber(vm, 5); 837 837 838 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 838 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 839 839 840 840 tic_api_rect(tic, x, y, w, h, color); 841 841 } ··· 848 848 s32 h = getWrenNumber(vm, 4); 849 849 s32 color = getWrenNumber(vm, 5); 850 850 851 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 851 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 852 852 853 853 tic_api_rectb(tic, x, y, w, h, color); 854 854 } ··· 864 864 865 865 s32 color = getWrenNumber(vm, 7); 866 866 867 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 867 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 868 868 869 869 tic_api_tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); 870 870 } ··· 873 873 { 874 874 int top = wrenGetSlotCount(vm); 875 875 876 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 876 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 877 877 878 878 tic_api_cls(tic, top == 1 ? 0 : getWrenNumber(vm, 1)); 879 879 } ··· 882 882 { 883 883 s32 top = wrenGetSlotCount(vm); 884 884 885 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 885 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 886 886 887 887 if(top == 1) 888 888 { ··· 901 901 902 902 static void wren_peek(WrenVM* vm) 903 903 { 904 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 904 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 905 905 906 906 s32 address = getWrenNumber(vm, 1); 907 907 ··· 910 910 911 911 static void wren_poke(WrenVM* vm) 912 912 { 913 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 913 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 914 914 915 915 s32 address = getWrenNumber(vm, 1); 916 916 u8 value = getWrenNumber(vm, 2) & 0xff; ··· 920 920 921 921 static void wren_peek4(WrenVM* vm) 922 922 { 923 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 923 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 924 924 925 925 s32 address = getWrenNumber(vm, 1); 926 926 ··· 929 929 930 930 static void wren_poke4(WrenVM* vm) 931 931 { 932 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 932 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 933 933 934 934 s32 address = getWrenNumber(vm, 1); 935 935 u8 value = getWrenNumber(vm, 2); ··· 943 943 s32 src = getWrenNumber(vm, 2); 944 944 s32 size = getWrenNumber(vm, 3); 945 945 946 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 946 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 947 947 tic_api_memcpy(tic, dest, src, size); 948 948 } 949 949 ··· 953 953 u8 value = getWrenNumber(vm, 2); 954 954 s32 size = getWrenNumber(vm, 3); 955 955 956 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 956 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 957 957 tic_api_memset(tic, dest, value, size); 958 958 } 959 959 960 960 static void wren_pmem(WrenVM* vm) 961 961 { 962 962 s32 top = wrenGetSlotCount(vm); 963 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 963 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 964 964 965 965 u32 index = getWrenNumber(vm, 1); 966 966 ··· 982 982 { 983 983 s32 top = wrenGetSlotCount(vm); 984 984 985 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 985 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 986 986 987 987 s32 index = getWrenNumber(vm, 1); 988 988 ··· 1058 1058 { 1059 1059 s32 top = wrenGetSlotCount(vm); 1060 1060 1061 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1061 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1062 1062 1063 1063 s32 track = -1; 1064 1064 s32 frame = -1; ··· 1096 1096 1097 1097 static void wren_time(WrenVM* vm) 1098 1098 { 1099 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1099 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1100 1100 1101 1101 wrenSetSlotDouble(vm, 0, tic_api_time(tic)); 1102 1102 } 1103 1103 1104 1104 static void wren_tstamp(WrenVM* vm) 1105 1105 { 1106 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1106 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1107 1107 1108 1108 wrenSetSlotDouble(vm, 0, tic_api_tstamp(tic)); 1109 1109 } 1110 1110 1111 1111 static void wren_sync(WrenVM* vm) 1112 1112 { 1113 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1113 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1114 1114 1115 1115 bool toCart = false; 1116 1116 u32 mask = 0; ··· 1140 1140 1141 1141 static void wren_reset(WrenVM* vm) 1142 1142 { 1143 - tic_machine* machine = getWrenMachine(vm); 1143 + tic_core* core = getWrenCore(vm); 1144 1144 1145 - machine->state.initialized = false; 1145 + core->state.initialized = false; 1146 1146 } 1147 1147 1148 1148 static void wren_exit(WrenVM* vm) 1149 1149 { 1150 - tic_api_exit((tic_mem*)getWrenMachine(vm)); 1150 + tic_api_exit((tic_mem*)getWrenCore(vm)); 1151 1151 } 1152 1152 1153 1153 static void wren_fget(WrenVM* vm) 1154 1154 { 1155 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1155 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1156 1156 1157 1157 s32 top = wrenGetSlotCount(vm); 1158 1158 ··· 1173 1173 1174 1174 static void wren_fset(WrenVM* vm) 1175 1175 { 1176 - tic_mem* tic = (tic_mem*)getWrenMachine(vm); 1176 + tic_mem* tic = (tic_mem*)getWrenCore(vm); 1177 1177 s32 top = wrenGetSlotCount(vm); 1178 1178 1179 1179 if(top > 1) ··· 1318 1318 return foreignTicMethods(fullName); 1319 1319 } 1320 1320 1321 - static void initAPI(tic_machine* machine) 1321 + static void initAPI(tic_core* core) 1322 1322 { 1323 - wrenSetUserData(machine->wren, machine); 1323 + wrenSetUserData(core->wren, core); 1324 1324 1325 - if (wrenInterpret(machine->wren, "main", tic_wren_api) != WREN_RESULT_SUCCESS) 1325 + if (wrenInterpret(core->wren, "main", tic_wren_api) != WREN_RESULT_SUCCESS) 1326 1326 { 1327 - machine->data->error(machine->data->data, "can't load TIC wren api"); 1327 + core->data->error(core->data->data, "can't load TIC wren api"); 1328 1328 } 1329 1329 } 1330 1330 1331 1331 static void reportError(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message) 1332 1332 { 1333 - tic_machine* machine = getWrenMachine(vm); 1333 + tic_core* core = getWrenCore(vm); 1334 1334 1335 1335 char buffer[1024]; 1336 1336 ··· 1341 1341 snprintf(buffer, sizeof buffer, "%d, \"%s\"",line, message); 1342 1342 } 1343 1343 1344 - machine->data->error(machine->data->data, buffer); 1344 + core->data->error(core->data->data, buffer); 1345 1345 } 1346 1346 1347 1347 static void writeFn(WrenVM* vm, const char* text) 1348 1348 { 1349 - tic_machine* machine = getWrenMachine(vm); 1349 + tic_core* core = getWrenCore(vm); 1350 1350 u8 color = tic_color_8; 1351 - machine->data->trace(machine->data->data, text ? text : "null", color); 1351 + core->data->trace(core->data->data, text ? text : "null", color); 1352 1352 } 1353 1353 1354 1354 static bool initWren(tic_mem* tic, const char* code) 1355 1355 { 1356 - tic_machine* machine = (tic_machine*)tic; 1356 + tic_core* core = (tic_core*)tic; 1357 1357 closeWren(tic); 1358 1358 1359 1359 WrenConfiguration config; ··· 1364 1364 config.errorFn = reportError; 1365 1365 config.writeFn = writeFn; 1366 1366 1367 - WrenVM* vm = machine->wren = wrenNewVM(&config); 1367 + WrenVM* vm = core->wren = wrenNewVM(&config); 1368 1368 1369 - initAPI(machine); 1369 + initAPI(core); 1370 1370 1371 - if (wrenInterpret(machine->wren, "main", code) != WREN_RESULT_SUCCESS) 1371 + if (wrenInterpret(core->wren, "main", code) != WREN_RESULT_SUCCESS) 1372 1372 { 1373 1373 return false; 1374 1374 } ··· 1391 1391 wrenEnsureSlots(vm, 1); 1392 1392 wrenSetSlotHandle(vm, 0, game_class); 1393 1393 wrenCall(vm, new_handle); 1394 - wrenReleaseHandle(machine->wren, game_class); // release game class handle 1394 + wrenReleaseHandle(core->wren, game_class); // release game class handle 1395 1395 game_class = NULL; 1396 1396 if (wrenGetSlotCount(vm) == 0) 1397 1397 { 1398 - machine->data->error(machine->data->data, "Error in game class :("); 1398 + core->data->error(core->data->data, "Error in game class :("); 1399 1399 return false; 1400 1400 } 1401 1401 game_class = wrenGetSlotHandle(vm, 0); // handle from game object 1402 1402 } else { 1403 - machine->data->error(machine->data->data, "'Game class' isn't found :("); 1403 + core->data->error(core->data->data, "'Game class' isn't found :("); 1404 1404 return false; 1405 1405 } 1406 1406 ··· 1409 1409 1410 1410 static void callWrenTick(tic_mem* tic) 1411 1411 { 1412 - tic_machine* machine = (tic_machine*)tic; 1413 - WrenVM* vm = machine->wren; 1412 + tic_core* core = (tic_core*)tic; 1413 + WrenVM* vm = core->wren; 1414 1414 1415 1415 if(vm && game_class) 1416 1416 { ··· 1422 1422 1423 1423 static void callWrenScanline(tic_mem* tic, s32 row, void* data) 1424 1424 { 1425 - tic_machine* machine = (tic_machine*)tic; 1426 - WrenVM* vm = machine->wren; 1425 + tic_core* core = (tic_core*)tic; 1426 + WrenVM* vm = core->wren; 1427 1427 1428 1428 if(vm && game_class) 1429 1429 { ··· 1436 1436 1437 1437 static void callWrenOverline(tic_mem* tic, void* data) 1438 1438 { 1439 - tic_machine* machine = (tic_machine*)tic; 1440 - WrenVM* vm = machine->wren; 1439 + tic_core* core = (tic_core*)tic; 1440 + WrenVM* vm = core->wren; 1441 1441 1442 1442 if (vm && game_class) 1443 1443 { ··· 1518 1518 1519 1519 static void evalWren(tic_mem* tic, const char* code) 1520 1520 { 1521 - tic_machine* machine = (tic_machine*)tic; 1522 - wrenInterpret(machine->wren, "main", code); 1521 + tic_core* core = (tic_core*)tic; 1522 + wrenInterpret(core->wren, "main", code); 1523 1523 } 1524 1524 1525 1525 static const tic_script_config WrenSyntaxConfig =
+1 -1
src/core/cart.c src/cart.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "core/cart.h" 23 + #include "cart.h" 24 24 #include "tools.h" 25 25 #include <string.h> 26 26 #include <stdlib.h>
src/core/cart.h src/cart.h
+766
src/core/core.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 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 "api.h" 24 + #include "core.h" 25 + #include "tilesheet.h" 26 + 27 + #include <assert.h> 28 + #include <string.h> 29 + #include <stdlib.h> 30 + #include <stdio.h> 31 + #include <ctype.h> 32 + #include <stddef.h> 33 + #include <time.h> 34 + 35 + #ifdef _3DS 36 + #include <3ds.h> 37 + #endif 38 + 39 + STATIC_ASSERT(tic_bank_bits, TIC_BANK_BITS == 3); 40 + STATIC_ASSERT(tic_map, sizeof(tic_map) < 1024 * 32); 41 + STATIC_ASSERT(tic_vram, sizeof(tic_vram) == TIC_VRAM_SIZE); 42 + STATIC_ASSERT(tic_ram, sizeof(tic_ram) == TIC_RAM_SIZE); 43 + 44 + static inline u32* getOvrAddr(tic_mem* tic, s32 x, s32 y) 45 + { 46 + enum { Top = (TIC80_FULLHEIGHT - TIC80_HEIGHT) / 2 }; 47 + enum { Left = (TIC80_FULLWIDTH - TIC80_WIDTH) / 2 }; 48 + 49 + return tic->screen + x + (y << TIC80_FULLWIDTH_BITS) + (Left + Top * TIC80_FULLWIDTH); 50 + } 51 + 52 + static void setPixelOvr(tic_mem* tic, s32 x, s32 y, u8 color) 53 + { 54 + tic_core* core = (tic_core*)tic; 55 + 56 + *getOvrAddr(tic, x, y) = *(core->state.ovr.raw + color); 57 + } 58 + 59 + static u8 getPixelOvr(tic_mem* tic, s32 x, s32 y) 60 + { 61 + tic_core* core = (tic_core*)tic; 62 + 63 + u32 color = *getOvrAddr(tic, x, y); 64 + u32* pal = core->state.ovr.raw; 65 + 66 + for (s32 i = 0; i < TIC_PALETTE_SIZE; i++, pal++) 67 + if (*pal == color) 68 + return i; 69 + 70 + return 0; 71 + } 72 + 73 + static void drawHLineOvr(tic_mem* tic, s32 x1, s32 x2, s32 y, u8 color) 74 + { 75 + tic_core* core = (tic_core*)tic; 76 + u32 final_color = *(core->state.ovr.raw + color); 77 + for (s32 x = x1; x < x2; ++x) { 78 + *getOvrAddr(tic, x, y) = final_color; 79 + } 80 + } 81 + 82 + u8 tic_api_peek(tic_mem* memory, s32 address) 83 + { 84 + if (address >= 0 && address < sizeof(tic_ram)) 85 + return *((u8*)&memory->ram + address); 86 + 87 + return 0; 88 + } 89 + 90 + void tic_api_poke(tic_mem* memory, s32 address, u8 value) 91 + { 92 + if (address >= 0 && address < sizeof(tic_ram)) 93 + *((u8*)&memory->ram + address) = value; 94 + } 95 + 96 + u8 tic_api_peek4(tic_mem* memory, s32 address) 97 + { 98 + if (address >= 0 && address < sizeof(tic_ram) * 2) 99 + return tic_tool_peek4((u8*)&memory->ram, address); 100 + 101 + return 0; 102 + } 103 + 104 + void tic_api_poke4(tic_mem* memory, s32 address, u8 value) 105 + { 106 + if (address >= 0 && address < sizeof(tic_ram) * 2) 107 + tic_tool_poke4((u8*)&memory->ram, address, value); 108 + } 109 + 110 + void tic_api_memcpy(tic_mem* memory, s32 dst, s32 src, s32 size) 111 + { 112 + s32 bound = sizeof(tic_ram) - size; 113 + 114 + if (size >= 0 115 + && size <= sizeof(tic_ram) 116 + && dst >= 0 117 + && src >= 0 118 + && dst <= bound 119 + && src <= bound) 120 + { 121 + u8* base = (u8*)&memory->ram; 122 + memcpy(base + dst, base + src, size); 123 + } 124 + } 125 + 126 + void tic_api_memset(tic_mem* memory, s32 dst, u8 val, s32 size) 127 + { 128 + s32 bound = sizeof(tic_ram) - size; 129 + 130 + if (size >= 0 131 + && size <= sizeof(tic_ram) 132 + && dst >= 0 133 + && dst <= bound) 134 + { 135 + u8* base = (u8*)&memory->ram; 136 + memset(base + dst, val, size); 137 + } 138 + } 139 + 140 + void tic_api_trace(tic_mem* memory, const char* text, u8 color) 141 + { 142 + tic_core* core = (tic_core*)memory; 143 + core->data->trace(core->data->data, text ? text : "nil", color); 144 + } 145 + 146 + u32 tic_api_pmem(tic_mem* tic, s32 index, u32 value, bool set) 147 + { 148 + u32 old = tic->ram.persistent.data[index]; 149 + 150 + if (set) 151 + tic->ram.persistent.data[index] = value; 152 + 153 + return old; 154 + } 155 + 156 + void tic_api_exit(tic_mem* tic) 157 + { 158 + tic_core* core = (tic_core*)tic; 159 + core->data->exit(core->data->data); 160 + } 161 + 162 + void tic_api_sync(tic_mem* tic, u32 mask, s32 bank, bool toCart) 163 + { 164 + tic_core* core = (tic_core*)tic; 165 + 166 + static const struct { s32 bank; s32 ram; s32 size; } Sections[] = 167 + { 168 + {offsetof(tic_bank, tiles), offsetof(tic_ram, tiles), sizeof(tic_tiles) }, 169 + {offsetof(tic_bank, sprites), offsetof(tic_ram, sprites), sizeof(tic_tiles) }, 170 + {offsetof(tic_bank, map), offsetof(tic_ram, map), sizeof(tic_map) }, 171 + {offsetof(tic_bank, sfx), offsetof(tic_ram, sfx), sizeof(tic_sfx) }, 172 + {offsetof(tic_bank, music), offsetof(tic_ram, music), sizeof(tic_music) }, 173 + {offsetof(tic_bank, palette.scn), offsetof(tic_ram, vram.palette), sizeof(tic_palette) }, 174 + {offsetof(tic_bank, flags), offsetof(tic_ram, flags), sizeof(tic_flags) }, 175 + }; 176 + 177 + enum { Count = COUNT_OF(Sections), Mask = (1 << Count) - 1 }; 178 + 179 + if (mask == 0) mask = Mask; 180 + 181 + mask &= ~core->state.synced & Mask; 182 + 183 + assert(bank >= 0 && bank < TIC_BANKS); 184 + 185 + for (s32 i = 0; i < Count; i++) 186 + { 187 + if (mask & (1 << i)) 188 + toCart 189 + ? memcpy((u8*)&tic->cart.banks[bank] + Sections[i].bank, (u8*)&tic->ram + Sections[i].ram, Sections[i].size) 190 + : memcpy((u8*)&tic->ram + Sections[i].ram, (u8*)&tic->cart.banks[bank] + Sections[i].bank, Sections[i].size); 191 + } 192 + 193 + // copy OVR palette 194 + { 195 + enum { PaletteIndex = 5 }; 196 + 197 + if (mask & (1 << PaletteIndex)) 198 + toCart 199 + ? memcpy(&tic->cart.banks[bank].palette.ovr, &core->state.ovr.palette, sizeof(tic_palette)) 200 + : memcpy(&core->state.ovr.palette, &tic->cart.banks[bank].palette.ovr, sizeof(tic_palette)); 201 + } 202 + 203 + core->state.synced |= mask; 204 + } 205 + 206 + double tic_api_time(tic_mem* memory) 207 + { 208 + tic_core* core = (tic_core*)memory; 209 + return (double)((core->data->counter() - core->data->start) * 1000) / core->data->freq(); 210 + } 211 + 212 + s32 tic_api_tstamp(tic_mem* memory) 213 + { 214 + tic_core* core = (tic_core*)memory; 215 + return (s32)time(NULL); 216 + } 217 + 218 + static void setPixelDma(tic_mem* tic, s32 x, s32 y, u8 color) 219 + { 220 + tic_tool_poke4(tic->ram.vram.screen.data, y * TIC80_WIDTH + x, color); 221 + } 222 + 223 + static u8 getPixelDma(tic_mem* tic, s32 x, s32 y) 224 + { 225 + tic_core* core = (tic_core*)tic; 226 + 227 + return tic_tool_peek4(core->memory.ram.vram.screen.data, y * TIC80_WIDTH + x); 228 + } 229 + 230 + static void drawHLineDma(tic_mem* memory, s32 xl, s32 xr, s32 y, u8 color) 231 + { 232 + color = color << 4 | color; 233 + if (xl >= xr) return; 234 + if (xl & 1) { 235 + tic_tool_poke4(&memory->ram.vram.screen.data, y * TIC80_WIDTH + xl, color); 236 + xl++; 237 + } 238 + s32 count = (xr - xl) >> 1; 239 + u8* screen = memory->ram.vram.screen.data + ((y * TIC80_WIDTH + xl) >> 1); 240 + for (s32 i = 0; i < count; i++) *screen++ = color; 241 + if (xr & 1) { 242 + tic_tool_poke4(&memory->ram.vram.screen.data, y * TIC80_WIDTH + xr - 1, color); 243 + } 244 + } 245 + 246 + static void resetPalette(tic_mem* memory) 247 + { 248 + static const u8 DefaultMapping[] = { 16, 50, 84, 118, 152, 186, 220, 254 }; 249 + memcpy(memory->ram.vram.palette.data, memory->cart.bank0.palette.scn.data, sizeof(tic_palette)); 250 + memcpy(memory->ram.vram.mapping, DefaultMapping, sizeof DefaultMapping); 251 + } 252 + 253 + static void resetBlitSegment(tic_mem* memory) 254 + { 255 + memory->ram.vram.blit.segment = 2; 256 + } 257 + 258 + static const char* readMetatag(const char* code, const char* tag, const char* comment) 259 + { 260 + const char* start = NULL; 261 + 262 + { 263 + static char format[] = "%s %s:"; 264 + 265 + char* tagBuffer = malloc(strlen(format) + strlen(tag)); 266 + 267 + if (tagBuffer) 268 + { 269 + sprintf(tagBuffer, format, comment, tag); 270 + if ((start = strstr(code, tagBuffer))) 271 + start += strlen(tagBuffer); 272 + free(tagBuffer); 273 + } 274 + } 275 + 276 + if (start) 277 + { 278 + const char* end = strstr(start, "\n"); 279 + 280 + if (end) 281 + { 282 + while (*start <= ' ' && start < end) start++; 283 + while (*(end - 1) <= ' ' && end > start) end--; 284 + 285 + const s32 size = (s32)(end - start); 286 + 287 + char* value = (char*)malloc(size + 1); 288 + 289 + if (value) 290 + { 291 + memset(value, 0, size + 1); 292 + memcpy(value, start, size); 293 + 294 + return value; 295 + } 296 + } 297 + } 298 + 299 + return NULL; 300 + } 301 + 302 + static bool compareMetatag(const char* code, const char* tag, const char* value, const char* comment) 303 + { 304 + bool result = false; 305 + 306 + const char* str = readMetatag(code, tag, comment); 307 + 308 + if (str) 309 + { 310 + result = strcmp(str, value) == 0; 311 + free((void*)str); 312 + } 313 + 314 + return result; 315 + } 316 + 317 + const tic_script_config* tic_core_script_config(tic_mem* memory) 318 + { 319 + const char* code = memory->cart.code.data; 320 + 321 + #if defined(TIC_BUILD_WITH_MOON) 322 + if (compareMetatag(code, "script", "moon", getMoonScriptConfig()->singleComment) || 323 + compareMetatag(code, "script", "moonscript", getMoonScriptConfig()->singleComment)) 324 + return getMoonScriptConfig(); 325 + #endif 326 + 327 + #if defined(TIC_BUILD_WITH_FENNEL) 328 + if (compareMetatag(code, "script", "fennel", getFennelConfig()->singleComment)) 329 + return getFennelConfig(); 330 + #endif 331 + 332 + #if defined(TIC_BUILD_WITH_JS) 333 + if (compareMetatag(code, "script", "js", getJsScriptConfig()->singleComment) || 334 + compareMetatag(code, "script", "javascript", getJsScriptConfig()->singleComment)) 335 + return getJsScriptConfig(); 336 + #endif 337 + 338 + #if defined(TIC_BUILD_WITH_WREN) 339 + if (compareMetatag(code, "script", "wren", getWrenScriptConfig()->singleComment)) 340 + return getWrenScriptConfig(); 341 + #endif 342 + 343 + #if defined(TIC_BUILD_WITH_SQUIRREL) 344 + if (compareMetatag(code, "script", "squirrel", getSquirrelScriptConfig()->singleComment)) 345 + return getSquirrelScriptConfig(); 346 + #endif 347 + 348 + #if defined(TIC_BUILD_WITH_LUA) 349 + return getLuaScriptConfig(); 350 + #elif defined(TIC_BUILD_WITH_JS) 351 + return getJsScriptConfig(); 352 + #elif defined(TIC_BUILD_WITH_WREN) 353 + return getWrenScriptConfig(); 354 + #elif defined(TIC_BUILD_WITH_SQUIRREL) 355 + return getSquirrelScriptConfig(); 356 + #endif 357 + } 358 + 359 + static void updateSaveid(tic_mem* memory) 360 + { 361 + memset(memory->saveid, 0, sizeof memory->saveid); 362 + const char* saveid = readMetatag(memory->cart.code.data, "saveid", tic_core_script_config(memory)->singleComment); 363 + if (saveid) 364 + { 365 + strncpy(memory->saveid, saveid, TIC_SAVEID_SIZE - 1); 366 + free((void*)saveid); 367 + } 368 + } 369 + 370 + static void soundClear(tic_mem* memory) 371 + { 372 + tic_core* core = (tic_core*)memory; 373 + 374 + for (s32 i = 0; i < TIC_SOUND_CHANNELS; i++) 375 + { 376 + static const tic_channel_data EmptyChannel = 377 + { 378 + .tick = -1, 379 + .pos = NULL, 380 + .index = -1, 381 + .note = 0, 382 + .volume = {0, 0}, 383 + .speed = 0, 384 + .duration = -1, 385 + }; 386 + 387 + memcpy(&core->state.music.channels[i], &EmptyChannel, sizeof EmptyChannel); 388 + memcpy(&core->state.sfx.channels[i], &EmptyChannel, sizeof EmptyChannel); 389 + 390 + memset(core->state.sfx.channels[i].pos = &memory->ram.sfxpos[i], -1, sizeof(tic_sfx_pos)); 391 + memset(core->state.music.channels[i].pos = &core->state.music.sfxpos[i], -1, sizeof(tic_sfx_pos)); 392 + } 393 + 394 + memset(&memory->ram.registers, 0, sizeof memory->ram.registers); 395 + memset(memory->samples.buffer, 0, memory->samples.size); 396 + 397 + tic_api_music(memory, -1, 0, 0, false, false); 398 + } 399 + 400 + static void resetDma(tic_mem* memory) 401 + { 402 + tic_core* core = (tic_core*)memory; 403 + core->state.setpix = setPixelDma; 404 + core->state.getpix = getPixelDma; 405 + core->state.drawhline = drawHLineDma; 406 + } 407 + 408 + void tic_api_reset(tic_mem* memory) 409 + { 410 + resetPalette(memory); 411 + resetBlitSegment(memory); 412 + 413 + memset(&memory->ram.vram.vars, 0, sizeof memory->ram.vram.vars); 414 + 415 + tic_api_clip(memory, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); 416 + 417 + soundClear(memory); 418 + 419 + tic_core* core = (tic_core*)memory; 420 + core->state.initialized = false; 421 + core->state.scanline = NULL; 422 + core->state.ovr.callback = NULL; 423 + 424 + resetDma(memory); 425 + 426 + updateSaveid(memory); 427 + } 428 + 429 + static void initCover(tic_mem* tic) 430 + { 431 + const tic_cover_image* cover = &tic->cart.cover; 432 + 433 + if (cover->size) 434 + { 435 + gif_image* image = gif_read_data(cover->data, cover->size); 436 + 437 + if (image) 438 + { 439 + if (image->width == TIC80_WIDTH && image->height == TIC80_HEIGHT) 440 + { 441 + enum { Size = TIC80_WIDTH * TIC80_HEIGHT }; 442 + 443 + for (s32 i = 0; i < Size; i++) 444 + { 445 + const gif_color* c = &image->palette[image->buffer[i]]; 446 + u8 color = tic_tool_find_closest_color(tic->cart.bank0.palette.scn.colors, c); 447 + tic_tool_poke4(tic->ram.vram.screen.data, i, color); 448 + } 449 + } 450 + 451 + gif_close(image); 452 + } 453 + } 454 + } 455 + 456 + static void cart2ram(tic_mem* memory) 457 + { 458 + static const u8 Font[] = 459 + { 460 + #include "font.inl" 461 + }; 462 + 463 + memcpy(memory->ram.font.data, Font, sizeof Font); 464 + 465 + tic_api_sync(memory, 0, 0, false); 466 + initCover(memory); 467 + } 468 + 469 + void tic_core_tick(tic_mem* tic, tic_tick_data* data) 470 + { 471 + tic_core* core = (tic_core*)tic; 472 + 473 + core->data = data; 474 + 475 + if (!core->state.initialized) 476 + { 477 + const char* code = tic->cart.code.data; 478 + 479 + bool done = false; 480 + const tic_script_config* config = NULL; 481 + 482 + if (strlen(code)) 483 + { 484 + config = tic_core_script_config(tic); 485 + cart2ram(tic); 486 + 487 + core->state.synced = 0; 488 + tic->input.data = 0; 489 + 490 + if (compareMetatag(code, "input", "mouse", config->singleComment)) 491 + tic->input.mouse = 1; 492 + else if (compareMetatag(code, "input", "gamepad", config->singleComment)) 493 + tic->input.gamepad = 1; 494 + else if (compareMetatag(code, "input", "keyboard", config->singleComment)) 495 + tic->input.keyboard = 1; 496 + else tic->input.data = -1; // default is all enabled 497 + 498 + data->start = data->counter(); 499 + 500 + done = config->init(tic, code); 501 + } 502 + else 503 + { 504 + core->data->error(core->data->data, "the code is empty"); 505 + } 506 + 507 + if (done) 508 + { 509 + core->state.tick = config->tick; 510 + core->state.scanline = config->scanline; 511 + core->state.ovr.callback = config->overline; 512 + 513 + core->state.initialized = true; 514 + } 515 + else return; 516 + } 517 + 518 + { 519 + if (!tic->input.keyboard) 520 + ZEROMEM(tic->ram.input.keyboard); 521 + 522 + if (!tic->input.gamepad) 523 + ZEROMEM(tic->ram.input.gamepads); 524 + 525 + if (!tic->input.mouse) 526 + ZEROMEM(tic->ram.input.mouse); 527 + } 528 + 529 + core->state.tick(tic); 530 + } 531 + 532 + void tic_core_pause(tic_mem* memory) 533 + { 534 + tic_core* core = (tic_core*)memory; 535 + 536 + memcpy(&core->pause.state, &core->state, sizeof(tic_core_state_data)); 537 + memcpy(&core->pause.ram, &memory->ram, sizeof(tic_ram)); 538 + core->pause.input = memory->input.data; 539 + memset(&core->state.ovr, 0, sizeof core->state.ovr); 540 + 541 + if (core->data) 542 + { 543 + core->pause.time.start = core->data->start; 544 + core->pause.time.paused = core->data->counter(); 545 + } 546 + } 547 + 548 + void tic_core_resume(tic_mem* memory) 549 + { 550 + tic_core* core = (tic_core*)memory; 551 + 552 + if (core->data) 553 + { 554 + memcpy(&core->state, &core->pause.state, sizeof(tic_core_state_data)); 555 + memcpy(&memory->ram, &core->pause.ram, sizeof(tic_ram)); 556 + memory->input.data = core->pause.input; 557 + core->data->start = core->pause.time.start + core->data->counter() - core->pause.time.paused; 558 + } 559 + } 560 + 561 + void tic_core_close(tic_mem* memory) 562 + { 563 + tic_core* core = (tic_core*)memory; 564 + 565 + core->state.initialized = false; 566 + 567 + #if defined(TIC_BUILD_WITH_SQUIRREL) 568 + getSquirrelScriptConfig()->close(memory); 569 + #endif 570 + 571 + #if defined(TIC_BUILD_WITH_LUA) 572 + getLuaScriptConfig()->close(memory); 573 + 574 + # if defined(TIC_BUILD_WITH_MOON) 575 + getMoonScriptConfig()->close(memory); 576 + # endif 577 + 578 + # if defined(TIC_BUILD_WITH_FENNEL) 579 + getFennelConfig()->close(memory); 580 + # endif 581 + 582 + #endif /* defined(TIC_BUILD_WITH_LUA) */ 583 + 584 + 585 + #if defined(TIC_BUILD_WITH_JS) 586 + getJsScriptConfig()->close(memory); 587 + #endif 588 + 589 + #if defined(TIC_BUILD_WITH_WREN) 590 + getWrenScriptConfig()->close(memory); 591 + #endif 592 + 593 + blip_delete(core->blip.left); 594 + blip_delete(core->blip.right); 595 + 596 + free(memory->samples.buffer); 597 + free(core); 598 + } 599 + 600 + void tic_core_tick_start(tic_mem* memory) 601 + { 602 + tick_core_sound_tick_start(memory); 603 + tic_core_tick_io(memory); 604 + 605 + tic_core* core = (tic_core*)memory; 606 + core->state.synced = 0; 607 + resetDma(memory); 608 + } 609 + 610 + void tic_core_tick_end(tic_mem* memory) 611 + { 612 + tic_core* core = (tic_core*)memory; 613 + tic80_input* input = &core->memory.ram.input; 614 + 615 + core->state.gamepads.previous.data = input->gamepads.data; 616 + core->state.keyboard.previous.data = input->keyboard.data; 617 + 618 + tick_core_sound_tick_end(memory); 619 + 620 + core->state.setpix = setPixelOvr; 621 + core->state.getpix = getPixelOvr; 622 + core->state.drawhline = drawHLineOvr; 623 + } 624 + 625 + // copied from SDL2 626 + static inline void memset4(void* dst, u32 val, u32 dwords) 627 + { 628 + #if defined(__GNUC__) && defined(i386) 629 + s32 u0, u1, u2; 630 + __asm__ __volatile__( 631 + "cld \n\t" 632 + "rep ; stosl \n\t" 633 + : "=&D" (u0), "=&a" (u1), "=&c" (u2) 634 + : "0" (dst), "1" (val), "2" (dwords) 635 + : "memory" 636 + ); 637 + #else 638 + u32 _n = (dwords + 3) / 4; 639 + u32* _p = (u32*)dst; 640 + u32 _val = (val); 641 + if (dwords == 0) 642 + return; 643 + switch (dwords % 4) 644 + { 645 + case 0: do { 646 + *_p++ = _val; 647 + case 3: *_p++ = _val; 648 + case 2: *_p++ = _val; 649 + case 1: *_p++ = _val; 650 + } while (--_n); 651 + } 652 + #endif 653 + } 654 + 655 + void tic_core_blit_ex(tic_mem* tic, tic80_pixel_color_format fmt, tic_scanline scanline, tic_overline overline, void* data) 656 + { 657 + // init OVR palette 658 + { 659 + tic_core* core = (tic_core*)tic; 660 + 661 + const tic_palette* ovr = &core->state.ovr.palette; 662 + bool ovrEmpty = true; 663 + for (s32 i = 0; i < sizeof(tic_palette); i++) 664 + if (ovr->data[i]) 665 + ovrEmpty = false; 666 + 667 + memcpy(core->state.ovr.raw, tic_tool_palette_blit(ovrEmpty ? &tic->ram.vram.palette : ovr, fmt), sizeof core->state.ovr.raw); 668 + } 669 + 670 + if (scanline) 671 + scanline(tic, 0, data); 672 + 673 + const u32* pal = tic_tool_palette_blit(&tic->ram.vram.palette, fmt); 674 + 675 + enum { Top = (TIC80_FULLHEIGHT - TIC80_HEIGHT) / 2, Bottom = Top }; 676 + enum { Left = (TIC80_FULLWIDTH - TIC80_WIDTH) / 2, Right = Left }; 677 + 678 + u32* out = tic->screen; 679 + 680 + memset4(&out[0 * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH * Top); 681 + 682 + u32* rowPtr = out + (Top * TIC80_FULLWIDTH); 683 + for (s32 r = 0; r < TIC80_HEIGHT; r++, rowPtr += TIC80_FULLWIDTH) 684 + { 685 + u32* colPtr = rowPtr + Left; 686 + memset4(rowPtr, pal[tic->ram.vram.vars.border], Left); 687 + 688 + s32 pos = (r + tic->ram.vram.vars.offset.y + TIC80_HEIGHT) % TIC80_HEIGHT * TIC80_WIDTH >> 1; 689 + 690 + u32 x = (-tic->ram.vram.vars.offset.x + TIC80_WIDTH) % TIC80_WIDTH; 691 + for (s32 c = 0; c < TIC80_WIDTH / 2; c++) 692 + { 693 + u8 val = ((u8*)tic->ram.vram.screen.data)[pos + c]; 694 + *(colPtr + (x++ % TIC80_WIDTH)) = pal[val & 0xf]; 695 + *(colPtr + (x++ % TIC80_WIDTH)) = pal[val >> 4]; 696 + } 697 + 698 + memset4(rowPtr + (TIC80_FULLWIDTH - Right), pal[tic->ram.vram.vars.border], Right); 699 + 700 + if (scanline && (r < TIC80_HEIGHT - 1)) 701 + { 702 + scanline(tic, r + 1, data); 703 + pal = tic_tool_palette_blit(&tic->ram.vram.palette, fmt); 704 + } 705 + } 706 + 707 + memset4(&out[(TIC80_FULLHEIGHT - Bottom) * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH * Bottom); 708 + 709 + if (overline) 710 + overline(tic, data); 711 + 712 + } 713 + 714 + static inline void scanline(tic_mem* memory, s32 row, void* data) 715 + { 716 + tic_core* core = (tic_core*)memory; 717 + 718 + if (core->state.initialized) 719 + core->state.scanline(memory, row, data); 720 + } 721 + 722 + static inline void overline(tic_mem* memory, void* data) 723 + { 724 + tic_core* core = (tic_core*)memory; 725 + 726 + if (core->state.initialized) 727 + core->state.ovr.callback(memory, data); 728 + } 729 + 730 + void tic_core_blit(tic_mem* tic, tic80_pixel_color_format fmt) 731 + { 732 + tic_core_blit_ex(tic, fmt, scanline, overline, NULL); 733 + } 734 + 735 + tic_mem* tic_core_create(s32 samplerate) 736 + { 737 + tic_core* core = (tic_core*)malloc(sizeof(tic_core)); 738 + memset(core, 0, sizeof(tic_core)); 739 + 740 + if (core != (tic_core*)&core->memory) 741 + { 742 + free(core); 743 + return NULL; 744 + } 745 + 746 + core->memory.screen_format = TIC80_PIXEL_COLOR_RGBA8888; 747 + core->samplerate = samplerate; 748 + #ifdef _3DS 749 + // To feed texture data directly to the 3DS GPU, linearly allocated memory is required, which is 750 + // not guaranteed by malloc. 751 + // Additionally, allocate TIC80_FULLHEIGHT + 1 lines to minimize glitches in linear scaling mode. 752 + core->memory.screen = linearAlloc(TIC80_FULLWIDTH * (TIC80_FULLHEIGHT + 1) * sizeof(u32)); 753 + #endif 754 + core->memory.samples.size = samplerate * TIC_STEREO_CHANNELS / TIC80_FRAMERATE * sizeof(s16); 755 + core->memory.samples.buffer = malloc(core->memory.samples.size); 756 + 757 + core->blip.left = blip_new(samplerate / 10); 758 + core->blip.right = blip_new(samplerate / 10); 759 + 760 + blip_set_rates(core->blip.left, CLOCKRATE, samplerate); 761 + blip_set_rates(core->blip.right, CLOCKRATE, samplerate); 762 + 763 + tic_api_reset(&core->memory); 764 + 765 + return &core->memory; 766 + }
+768
src/core/draw.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 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 "api.h" 24 + #include "core.h" 25 + #include "tilesheet.h" 26 + 27 + #include <string.h> 28 + #include <math.h> 29 + 30 + #define TRANSPARENT_COLOR 255 31 + 32 + static tic_tilesheet getTileSheetFromSegment(tic_mem* memory, u8 segment) 33 + { 34 + u8* src; 35 + switch (segment) { 36 + case 0: 37 + case 1: 38 + src = (u8*)&memory->ram.font.data; break; 39 + default: 40 + src = (u8*)&memory->ram.tiles.data; break; 41 + } 42 + 43 + return tic_tilesheet_get(segment, src); 44 + } 45 + 46 + static u8* getPalette(tic_mem* tic, u8* colors, u8 count) 47 + { 48 + static u8 mapping[TIC_PALETTE_SIZE]; 49 + for (s32 i = 0; i < TIC_PALETTE_SIZE; i++) mapping[i] = tic_tool_peek4(tic->ram.vram.mapping, i); 50 + for (s32 i = 0; i < count; i++) mapping[colors[i]] = TRANSPARENT_COLOR; 51 + return mapping; 52 + } 53 + 54 + static inline u8 mapColor(tic_mem* tic, u8 color) 55 + { 56 + return tic_tool_peek4(tic->ram.vram.mapping, color & 0xf); 57 + } 58 + 59 + static void setPixel(tic_core* core, s32 x, s32 y, u8 color) 60 + { 61 + if (x < core->state.clip.l || y < core->state.clip.t || x >= core->state.clip.r || y >= core->state.clip.b) return; 62 + 63 + core->state.setpix(&core->memory, x, y, color); 64 + } 65 + 66 + static u8 getPixel(tic_core* core, s32 x, s32 y) 67 + { 68 + if (x < 0 || y < 0 || x >= TIC80_WIDTH || y >= TIC80_HEIGHT) return 0; 69 + 70 + return core->state.getpix(&core->memory, x, y); 71 + } 72 + 73 + #define EARLY_CLIP(x, y, width, height) \ 74 + ( \ 75 + (((y)+(height)-1) < core->state.clip.t) \ 76 + || (((x)+(width)-1) < core->state.clip.l) \ 77 + || ((y) >= core->state.clip.b) \ 78 + || ((x) >= core->state.clip.r) \ 79 + ) 80 + 81 + static void drawHLine(tic_core* core, s32 x, s32 y, s32 width, u8 color) 82 + { 83 + if (y < core->state.clip.t || core->state.clip.b <= y) return; 84 + 85 + s32 xl = MAX(x, core->state.clip.l); 86 + s32 xr = MIN(x + width, core->state.clip.r); 87 + 88 + core->state.drawhline(&core->memory, xl, xr, y, color); 89 + } 90 + 91 + static void drawVLine(tic_core* core, s32 x, s32 y, s32 height, u8 color) 92 + { 93 + if (x < core->state.clip.l || core->state.clip.r <= x) return; 94 + 95 + s32 yl = y < 0 ? 0 : y; 96 + s32 yr = y + height >= TIC80_HEIGHT ? TIC80_HEIGHT : y + height; 97 + 98 + for (s32 i = yl; i < yr; ++i) 99 + setPixel(core, x, i, color); 100 + } 101 + 102 + static void drawRect(tic_core* core, s32 x, s32 y, s32 width, s32 height, u8 color) 103 + { 104 + for (s32 i = y; i < y + height; ++i) 105 + drawHLine(core, x, i, width, color); 106 + } 107 + 108 + static void drawRectBorder(tic_core* core, s32 x, s32 y, s32 width, s32 height, u8 color) 109 + { 110 + drawHLine(core, x, y, width, color); 111 + drawHLine(core, x, y + height - 1, width, color); 112 + 113 + drawVLine(core, x, y, height, color); 114 + drawVLine(core, x + width - 1, y, height, color); 115 + } 116 + 117 + #define DRAW_TILE_BODY(X, Y) do {\ 118 + for(s32 py=sy; py < ey; py++, y++) \ 119 + { \ 120 + s32 xx = x; \ 121 + for(s32 px=sx; px < ex; px++, xx++) \ 122 + { \ 123 + u8 color = mapping[tic_tilesheet_gettilepix(tile, (X), (Y))];\ 124 + if(color != TRANSPARENT_COLOR) core->state.setpix(&core->memory, xx, y, color); \ 125 + } \ 126 + } \ 127 + } while(0) 128 + 129 + #define REVERT(X) (TIC_SPRITESIZE - 1 - (X)) 130 + 131 + static void drawTile(tic_core* core, tic_tileptr* tile, s32 x, s32 y, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 132 + { 133 + u8* mapping = getPalette(&core->memory, colors, count); 134 + 135 + rotate &= 0b11; 136 + u32 orientation = flip & 0b11; 137 + 138 + if (rotate == tic_90_rotate) orientation ^= 0b001; 139 + else if (rotate == tic_180_rotate) orientation ^= 0b011; 140 + else if (rotate == tic_270_rotate) orientation ^= 0b010; 141 + if (rotate == tic_90_rotate || rotate == tic_270_rotate) orientation |= 0b100; 142 + 143 + if (scale == 1) { 144 + // the most common path 145 + s32 sx, sy, ex, ey; 146 + sx = core->state.clip.l - x; if (sx < 0) sx = 0; 147 + sy = core->state.clip.t - y; if (sy < 0) sy = 0; 148 + ex = core->state.clip.r - x; if (ex > TIC_SPRITESIZE) ex = TIC_SPRITESIZE; 149 + ey = core->state.clip.b - y; if (ey > TIC_SPRITESIZE) ey = TIC_SPRITESIZE; 150 + y += sy; 151 + x += sx; 152 + switch (orientation) { 153 + case 0b100: DRAW_TILE_BODY(py, px); break; 154 + case 0b110: DRAW_TILE_BODY(REVERT(py), px); break; 155 + case 0b101: DRAW_TILE_BODY(py, REVERT(px)); break; 156 + case 0b111: DRAW_TILE_BODY(REVERT(py), REVERT(px)); break; 157 + case 0b000: DRAW_TILE_BODY(px, py); break; 158 + case 0b010: DRAW_TILE_BODY(px, REVERT(py)); break; 159 + case 0b001: DRAW_TILE_BODY(REVERT(px), py); break; 160 + case 0b011: DRAW_TILE_BODY(REVERT(px), REVERT(py)); break; 161 + } 162 + return; 163 + } 164 + 165 + if (EARLY_CLIP(x, y, TIC_SPRITESIZE * scale, TIC_SPRITESIZE * scale)) return; 166 + 167 + for (s32 py = 0; py < TIC_SPRITESIZE; py++, y += scale) 168 + { 169 + s32 xx = x; 170 + for (s32 px = 0; px < TIC_SPRITESIZE; px++, xx += scale) 171 + { 172 + s32 ix = orientation & 0b001 ? TIC_SPRITESIZE - px - 1 : px; 173 + s32 iy = orientation & 0b010 ? TIC_SPRITESIZE - py - 1 : py; 174 + if (orientation & 0b100) { 175 + s32 tmp = ix; ix = iy; iy = tmp; 176 + } 177 + u8 color = mapping[tic_tilesheet_gettilepix(tile, ix, iy)]; 178 + if (color != TRANSPARENT_COLOR) drawRect(core, xx, y, scale, scale, color); 179 + } 180 + } 181 + } 182 + 183 + #undef DRAW_TILE_BODY 184 + #undef REVERT 185 + 186 + static void drawSprite(tic_core* core, s32 index, s32 x, s32 y, s32 w, s32 h, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 187 + { 188 + tic_tilesheet sheet = getTileSheetFromSegment(&core->memory, core->memory.ram.vram.blit.segment); 189 + if (w == 1 && h == 1) { 190 + tic_tileptr tile = tic_tilesheet_gettile(&sheet, index, false); 191 + drawTile(core, &tile, x, y, colors, count, scale, flip, rotate); 192 + } 193 + else 194 + { 195 + s32 step = TIC_SPRITESIZE * scale; 196 + s32 cols = sheet.segment->sheet_width; 197 + 198 + const tic_flip vert_horz_flip = tic_horz_flip | tic_vert_flip; 199 + 200 + if (EARLY_CLIP(x, y, w * step, h * step)) return; 201 + 202 + for (s32 i = 0; i < w; i++) 203 + { 204 + for (s32 j = 0; j < h; j++) 205 + { 206 + s32 mx = i; 207 + s32 my = j; 208 + 209 + if (flip == tic_horz_flip || flip == vert_horz_flip) mx = w - 1 - i; 210 + if (flip == tic_vert_flip || flip == vert_horz_flip) my = h - 1 - j; 211 + 212 + if (rotate == tic_180_rotate) 213 + { 214 + mx = w - 1 - mx; 215 + my = h - 1 - my; 216 + } 217 + else if (rotate == tic_90_rotate) 218 + { 219 + if (flip == tic_no_flip || flip == vert_horz_flip) my = h - 1 - my; 220 + else mx = w - 1 - mx; 221 + } 222 + else if (rotate == tic_270_rotate) 223 + { 224 + if (flip == tic_no_flip || flip == vert_horz_flip) mx = w - 1 - mx; 225 + else my = h - 1 - my; 226 + } 227 + 228 + enum { Cols = TIC_SPRITESHEET_SIZE / TIC_SPRITESIZE }; 229 + 230 + 231 + tic_tileptr tile = tic_tilesheet_gettile(&sheet, index + mx + my * cols, false); 232 + if (rotate == 0 || rotate == 2) 233 + drawTile(core, &tile, x + i * step, y + j * step, colors, count, scale, flip, rotate); 234 + else 235 + drawTile(core, &tile, x + j * step, y + i * step, colors, count, scale, flip, rotate); 236 + } 237 + } 238 + } 239 + } 240 + 241 + static void drawMap(tic_core* core, const tic_map* src, s32 x, s32 y, s32 width, s32 height, s32 sx, s32 sy, u8* colors, s32 count, s32 scale, RemapFunc remap, void* data) 242 + { 243 + const s32 size = TIC_SPRITESIZE * scale; 244 + 245 + tic_tilesheet sheet = getTileSheetFromSegment(&core->memory, core->memory.ram.vram.blit.segment); 246 + 247 + for (s32 j = y, jj = sy; j < y + height; j++, jj += size) 248 + for (s32 i = x, ii = sx; i < x + width; i++, ii += size) 249 + { 250 + s32 mi = i; 251 + s32 mj = j; 252 + 253 + while (mi < 0) mi += TIC_MAP_WIDTH; 254 + while (mj < 0) mj += TIC_MAP_HEIGHT; 255 + while (mi >= TIC_MAP_WIDTH) mi -= TIC_MAP_WIDTH; 256 + while (mj >= TIC_MAP_HEIGHT) mj -= TIC_MAP_HEIGHT; 257 + 258 + s32 index = mi + mj * TIC_MAP_WIDTH; 259 + RemapResult retile = { *(src->data + index), tic_no_flip, tic_no_rotate }; 260 + 261 + if (remap) 262 + remap(data, mi, mj, &retile); 263 + 264 + tic_tileptr tile = tic_tilesheet_gettile(&sheet, retile.index, true); 265 + drawTile(core, &tile, ii, jj, colors, count, scale, retile.flip, retile.rotate); 266 + } 267 + } 268 + 269 + static s32 drawChar(tic_core* core, tic_tileptr* font_char, s32 x, s32 y, s32 scale, bool fixed, u8* mapping) 270 + { 271 + enum { Size = TIC_SPRITESIZE }; 272 + 273 + s32 j = 0, start = 0, end = Size; 274 + 275 + if (!fixed) { 276 + for (s32 i = 0; i < Size; i++) { 277 + for (j = 0; j < Size; j++) 278 + if (mapping[tic_tilesheet_gettilepix(font_char, i, j)] != TRANSPARENT_COLOR) break; 279 + if (j < Size) break; else start++; 280 + } 281 + for (s32 i = Size - 1; i >= start; i--) { 282 + for (j = 0; j < Size; j++) 283 + if (mapping[tic_tilesheet_gettilepix(font_char, i, j)] != TRANSPARENT_COLOR) break; 284 + if (j < Size) break; else end--; 285 + } 286 + } 287 + s32 width = end - start; 288 + 289 + if (EARLY_CLIP(x, y, Size * scale, Size * scale)) return width; 290 + 291 + s32 colStart = start, colStep = 1, rowStart = 0, rowStep = 1; 292 + 293 + for (s32 i = 0, col = colStart, xs = x; i < width; i++, col += colStep, xs += scale) 294 + { 295 + for (s32 j = 0, row = rowStart, ys = y; j < Size; j++, row += rowStep, ys += scale) 296 + { 297 + u8 color = tic_tilesheet_gettilepix(font_char, col, row); 298 + if (mapping[color] != TRANSPARENT_COLOR) 299 + drawRect(core, xs, ys, scale, scale, mapping[color]); 300 + } 301 + } 302 + return width; 303 + } 304 + 305 + static s32 drawText(tic_core* core, tic_tilesheet* font_face, const char* text, s32 x, s32 y, s32 width, s32 height, bool fixed, u8* mapping, s32 scale, bool alt) 306 + { 307 + s32 pos = x; 308 + s32 MAX = x; 309 + char sym = 0; 310 + 311 + while ((sym = *text++)) 312 + { 313 + if (sym == '\n') 314 + { 315 + if (pos > MAX) 316 + MAX = pos; 317 + 318 + pos = x; 319 + y += height * scale; 320 + } 321 + else { 322 + tic_tileptr font_char = tic_tilesheet_gettile(font_face, alt * TIC_FONT_CHARS / 2 + sym, true); 323 + s32 size = drawChar(core, &font_char, pos, y, scale, fixed, mapping); 324 + pos += ((!fixed && size) ? size + 1 : width) * scale; 325 + } 326 + } 327 + 328 + return pos > MAX ? pos - x : MAX - x; 329 + } 330 + 331 + void tic_api_clip(tic_mem* memory, s32 x, s32 y, s32 width, s32 height) 332 + { 333 + tic_core* core = (tic_core*)memory; 334 + 335 + core->state.clip.l = x; 336 + core->state.clip.t = y; 337 + core->state.clip.r = x + width; 338 + core->state.clip.b = y + height; 339 + 340 + if (core->state.clip.l < 0) core->state.clip.l = 0; 341 + if (core->state.clip.t < 0) core->state.clip.t = 0; 342 + if (core->state.clip.r > TIC80_WIDTH) core->state.clip.r = TIC80_WIDTH; 343 + if (core->state.clip.b > TIC80_HEIGHT) core->state.clip.b = TIC80_HEIGHT; 344 + } 345 + 346 + void tic_api_rect(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, u8 color) 347 + { 348 + tic_core* core = (tic_core*)memory; 349 + 350 + drawRect(core, x, y, width, height, mapColor(memory, color)); 351 + } 352 + 353 + void tic_api_cls(tic_mem* memory, u8 color) 354 + { 355 + static const tic_clip_data EmptyClip = { 0, 0, TIC80_WIDTH, TIC80_HEIGHT }; 356 + 357 + tic_core* core = (tic_core*)memory; 358 + 359 + if (memcmp(&core->state.clip, &EmptyClip, sizeof(tic_clip_data)) == 0) 360 + { 361 + color &= 0b00001111; 362 + memset(memory->ram.vram.screen.data, color | (color << TIC_PALETTE_BPP), sizeof(memory->ram.vram.screen.data)); 363 + } 364 + else 365 + { 366 + tic_api_rect(memory, core->state.clip.l, core->state.clip.t, core->state.clip.r - core->state.clip.l, core->state.clip.b - core->state.clip.t, color); 367 + } 368 + } 369 + 370 + s32 tic_api_font(tic_mem* memory, const char* text, s32 x, s32 y, u8 chromakey, s32 w, s32 h, bool fixed, s32 scale, bool alt) 371 + { 372 + u8* mapping = getPalette(memory, &chromakey, 1); 373 + 374 + // Compatibility : flip top and bottom of the spritesheet 375 + // to preserve tic_api_font's default target 376 + u8 segment = memory->ram.vram.blit.segment >> 1; 377 + u8 flipmask = 1; while (segment >>= 1) flipmask <<= 1; 378 + 379 + tic_tilesheet font_face = getTileSheetFromSegment(memory, memory->ram.vram.blit.segment ^ flipmask); 380 + return drawText((tic_core*)memory, &font_face, text, x, y, w, h, fixed, mapping, scale, alt); 381 + } 382 + 383 + s32 tic_api_print(tic_mem* memory, const char* text, s32 x, s32 y, u8 color, bool fixed, s32 scale, bool alt) 384 + { 385 + u8 mapping[] = { 255, color }; 386 + tic_tilesheet font_face = getTileSheetFromSegment(memory, 1); 387 + // Compatibility : print uses reduced width for non-fixed space 388 + u8 width = alt ? TIC_ALTFONT_WIDTH : TIC_FONT_WIDTH; 389 + if (!fixed) width -= 2; 390 + return drawText((tic_core*)memory, &font_face, text, x, y, width, TIC_FONT_HEIGHT, fixed, mapping, scale, alt); 391 + } 392 + 393 + void tic_api_spr(tic_mem* memory, s32 index, s32 x, s32 y, s32 w, s32 h, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 394 + { 395 + drawSprite((tic_core*)memory, index, x, y, w, h, colors, count, scale, flip, rotate); 396 + } 397 + 398 + static inline u8* getFlag(tic_mem* memory, s32 index, u8 flag) 399 + { 400 + static u8 stub = 0; 401 + if (index >= TIC_FLAGS || flag >= BITS_IN_BYTE) 402 + return &stub; 403 + 404 + return memory->ram.flags.data + index; 405 + } 406 + 407 + bool tic_api_fget(tic_mem* memory, s32 index, u8 flag) 408 + { 409 + return *getFlag(memory, index, flag) & (1 << flag); 410 + } 411 + 412 + void tic_api_fset(tic_mem* memory, s32 index, u8 flag, bool value) 413 + { 414 + if (value) 415 + *getFlag(memory, index, flag) |= (1 << flag); 416 + else 417 + *getFlag(memory, index, flag) &= ~(1 << flag); 418 + } 419 + 420 + u8 tic_api_pix(tic_mem* memory, s32 x, s32 y, u8 color, bool get) 421 + { 422 + tic_core* core = (tic_core*)memory; 423 + 424 + if (get) return getPixel(core, x, y); 425 + 426 + setPixel(core, x, y, mapColor(memory, color)); 427 + return 0; 428 + } 429 + 430 + void tic_api_rectb(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, u8 color) 431 + { 432 + tic_core* core = (tic_core*)memory; 433 + 434 + drawRectBorder(core, x, y, width, height, mapColor(memory, color)); 435 + } 436 + 437 + static struct 438 + { 439 + s16 Left[TIC80_HEIGHT]; 440 + s16 Right[TIC80_HEIGHT]; 441 + s32 ULeft[TIC80_HEIGHT]; 442 + s32 VLeft[TIC80_HEIGHT]; 443 + } SidesBuffer; 444 + 445 + static void initSidesBuffer() 446 + { 447 + for (s32 i = 0; i < COUNT_OF(SidesBuffer.Left); i++) 448 + SidesBuffer.Left[i] = TIC80_WIDTH, SidesBuffer.Right[i] = -1; 449 + } 450 + 451 + static void setSidePixel(s32 x, s32 y) 452 + { 453 + if (y >= 0 && y < TIC80_HEIGHT) 454 + { 455 + if (x < SidesBuffer.Left[y]) SidesBuffer.Left[y] = x; 456 + if (x > SidesBuffer.Right[y]) SidesBuffer.Right[y] = x; 457 + } 458 + } 459 + 460 + static void setSideTexPixel(s32 x, s32 y, float u, float v) 461 + { 462 + s32 yy = y; 463 + if (yy >= 0 && yy < TIC80_HEIGHT) 464 + { 465 + if (x < SidesBuffer.Left[yy]) 466 + { 467 + SidesBuffer.Left[yy] = x; 468 + SidesBuffer.ULeft[yy] = u * 65536.0f; 469 + SidesBuffer.VLeft[yy] = v * 65536.0f; 470 + } 471 + if (x > SidesBuffer.Right[yy]) 472 + { 473 + SidesBuffer.Right[yy] = x; 474 + } 475 + } 476 + } 477 + 478 + void tic_api_circ(tic_mem* memory, s32 xm, s32 ym, s32 radius, u8 color) 479 + { 480 + tic_core* core = (tic_core*)memory; 481 + 482 + initSidesBuffer(); 483 + 484 + s32 r = radius; 485 + s32 x = -r, y = 0, err = 2 - 2 * r; 486 + do 487 + { 488 + setSidePixel(xm - x, ym + y); 489 + setSidePixel(xm - y, ym - x); 490 + setSidePixel(xm + x, ym - y); 491 + setSidePixel(xm + y, ym + x); 492 + 493 + r = err; 494 + if (r <= y) err += ++y * 2 + 1; 495 + if (r > x || err > y) err += ++x * 2 + 1; 496 + } while (x < 0); 497 + 498 + s32 yt = MAX(core->state.clip.t, ym - radius); 499 + s32 yb = MIN(core->state.clip.b, ym + radius + 1); 500 + u8 final_color = mapColor(&core->memory, color); 501 + for (s32 y = yt; y < yb; y++) { 502 + s32 xl = MAX(SidesBuffer.Left[y], core->state.clip.l); 503 + s32 xr = MIN(SidesBuffer.Right[y] + 1, core->state.clip.r); 504 + core->state.drawhline(&core->memory, xl, xr, y, final_color); 505 + } 506 + } 507 + 508 + void tic_api_circb(tic_mem* memory, s32 xm, s32 ym, s32 radius, u8 color) 509 + { 510 + tic_core* core = (tic_core*)memory; 511 + u8 final_color = mapColor(memory, color); 512 + s32 r = radius; 513 + s32 x = -r, y = 0, err = 2 - 2 * r; 514 + do { 515 + setPixel(core, xm - x, ym + y, final_color); 516 + setPixel(core, xm - y, ym - x, final_color); 517 + setPixel(core, xm + x, ym - y, final_color); 518 + setPixel(core, xm + y, ym + x, final_color); 519 + r = err; 520 + if (r <= y) err += ++y * 2 + 1; 521 + if (r > x || err > y) err += ++x * 2 + 1; 522 + } while (x < 0); 523 + } 524 + 525 + typedef void(*linePixelFunc)(tic_mem* memory, s32 x, s32 y, u8 color); 526 + static void ticLine(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color, linePixelFunc func) 527 + { 528 + if (y0 > y1) 529 + { 530 + SWAP(x0, x1, s32); 531 + SWAP(y0, y1, s32); 532 + } 533 + 534 + s32 dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; 535 + s32 dy = y1 - y0; 536 + s32 err = (dx > dy ? dx : -dy) / 2, e2; 537 + 538 + for (;;) 539 + { 540 + func(memory, x0, y0, color); 541 + if (x0 == x1 && y0 == y1) break; 542 + e2 = err; 543 + if (e2 > -dx) { err -= dy; x0 += sx; } 544 + if (e2 < dy) { err += dx; y0++; } 545 + } 546 + } 547 + 548 + static void triPixelFunc(tic_mem* memory, s32 x, s32 y, u8 color) 549 + { 550 + setSidePixel(x, y); 551 + } 552 + 553 + void tic_api_tri(tic_mem* memory, s32 x1, s32 y1, s32 x2, s32 y2, s32 x3, s32 y3, u8 color) 554 + { 555 + tic_core* core = (tic_core*)memory; 556 + 557 + initSidesBuffer(); 558 + 559 + ticLine(memory, x1, y1, x2, y2, color, triPixelFunc); 560 + ticLine(memory, x2, y2, x3, y3, color, triPixelFunc); 561 + ticLine(memory, x3, y3, x1, y1, color, triPixelFunc); 562 + 563 + u8 final_color = mapColor(&core->memory, color); 564 + s32 yt = MAX(core->state.clip.t, MIN(y1, MIN(y2, y3))); 565 + s32 yb = MIN(core->state.clip.b, MAX(y1, MAX(y2, y3)) + 1); 566 + 567 + for (s32 y = yt; y < yb; y++) { 568 + s32 xl = MAX(SidesBuffer.Left[y], core->state.clip.l); 569 + s32 xr = MIN(SidesBuffer.Right[y] + 1, core->state.clip.r); 570 + core->state.drawhline(&core->memory, xl, xr, y, final_color); 571 + } 572 + } 573 + 574 + 575 + typedef struct 576 + { 577 + float x, y, u, v; 578 + } TexVert; 579 + 580 + 581 + static void ticTexLine(tic_mem* memory, TexVert* v0, TexVert* v1) 582 + { 583 + TexVert* top = v0; 584 + TexVert* bot = v1; 585 + 586 + if (bot->y < top->y) 587 + { 588 + top = v1; 589 + bot = v0; 590 + } 591 + 592 + float dy = bot->y - top->y; 593 + float step_x = (bot->x - top->x); 594 + float step_u = (bot->u - top->u); 595 + float step_v = (bot->v - top->v); 596 + 597 + if ((s32)dy != 0) 598 + { 599 + step_x /= dy; 600 + step_u /= dy; 601 + step_v /= dy; 602 + } 603 + 604 + float x = top->x; 605 + float y = top->y; 606 + float u = top->u; 607 + float v = top->v; 608 + 609 + if (y < .0f) 610 + { 611 + y = .0f - y; 612 + 613 + x += step_x * y; 614 + u += step_u * y; 615 + v += step_v * y; 616 + 617 + y = .0f; 618 + } 619 + 620 + s32 botY = bot->y; 621 + if (botY > TIC80_HEIGHT) 622 + botY = TIC80_HEIGHT; 623 + 624 + for (; y < botY; ++y) 625 + { 626 + setSideTexPixel(x, y, u, v); 627 + x += step_x; 628 + u += step_u; 629 + v += step_v; 630 + } 631 + } 632 + 633 + static void drawTexturedTriangle(tic_core* core, float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, bool use_map, u8* colors, s32 count) 634 + { 635 + tic_mem* memory = &core->memory; 636 + u8* mapping = getPalette(memory, colors, count); 637 + TexVert V0, V1, V2; 638 + 639 + const u8* map = memory->ram.map.data; 640 + tic_tilesheet sheet = getTileSheetFromSegment(memory, memory->ram.vram.blit.segment); 641 + 642 + V0.x = x1; V0.y = y1; V0.u = u1; V0.v = v1; 643 + V1.x = x2; V1.y = y2; V1.u = u2; V1.v = v2; 644 + V2.x = x3; V2.y = y3; V2.u = u3; V2.v = v3; 645 + 646 + // calculate the slope of the surface 647 + // use floats here 648 + double denom = (V0.x - V2.x) * (V1.y - V2.y) - (V1.x - V2.x) * (V0.y - V2.y); 649 + if (denom == 0.0) 650 + { 651 + return; 652 + } 653 + double id = 1.0 / denom; 654 + float dudx, dvdx; 655 + // this is the UV slope across the surface 656 + dudx = ((V0.u - V2.u) * (V1.y - V2.y) - (V1.u - V2.u) * (V0.y - V2.y)) * id; 657 + dvdx = ((V0.v - V2.v) * (V1.y - V2.y) - (V1.v - V2.v) * (V0.y - V2.y)) * id; 658 + // convert to fixed 659 + s32 dudxs = dudx * 65536.0f; 660 + s32 dvdxs = dvdx * 65536.0f; 661 + // fill the buffer 662 + initSidesBuffer(); 663 + // parse each line and decide where in the buffer to store them ( left or right ) 664 + ticTexLine(memory, &V0, &V1); 665 + ticTexLine(memory, &V1, &V2); 666 + ticTexLine(memory, &V2, &V0); 667 + 668 + for (s32 y = 0; y < TIC80_HEIGHT; y++) 669 + { 670 + // if it's backwards skip it 671 + s32 width = SidesBuffer.Right[y] - SidesBuffer.Left[y]; 672 + // if it's off top or bottom , skip this line 673 + if ((y < core->state.clip.t) || (y > core->state.clip.b)) 674 + width = 0; 675 + if (width > 0) 676 + { 677 + s32 u = SidesBuffer.ULeft[y]; 678 + s32 v = SidesBuffer.VLeft[y]; 679 + s32 left = SidesBuffer.Left[y]; 680 + s32 right = SidesBuffer.Right[y]; 681 + // check right edge, and CLAMP it 682 + if (right > core->state.clip.r) 683 + right = core->state.clip.r; 684 + // check left edge and offset UV's if we are off the left 685 + if (left < core->state.clip.l) 686 + { 687 + s32 dist = core->state.clip.l - SidesBuffer.Left[y]; 688 + u += dudxs * dist; 689 + v += dvdxs * dist; 690 + left = core->state.clip.l; 691 + } 692 + // are we drawing from the map . ok then at least check before the inner loop 693 + if (use_map == true) 694 + { 695 + for (s32 x = left; x < right; ++x) 696 + { 697 + enum { MapWidth = TIC_MAP_WIDTH * TIC_SPRITESIZE, MapHeight = TIC_MAP_HEIGHT * TIC_SPRITESIZE }; 698 + s32 iu = (u >> 16) % MapWidth; 699 + s32 iv = (v >> 16) % MapHeight; 700 + 701 + while (iu < 0) iu += MapWidth; 702 + while (iv < 0) iv += MapHeight; 703 + 704 + u8 tileindex = map[(iv >> 3) * TIC_MAP_WIDTH + (iu >> 3)]; 705 + tic_tileptr tile = tic_tilesheet_gettile(&sheet, tileindex, true); 706 + 707 + u8 color = mapping[tic_tilesheet_gettilepix(&tile, iu & 7, iv & 7)]; 708 + if (color != TRANSPARENT_COLOR) 709 + setPixel(core, x, y, color); 710 + u += dudxs; 711 + v += dvdxs; 712 + } 713 + } 714 + else 715 + { 716 + // direct from tile ram 717 + for (s32 x = left; x < right; ++x) 718 + { 719 + enum { SheetWidth = TIC_SPRITESHEET_SIZE, SheetHeight = TIC_SPRITESHEET_SIZE * TIC_SPRITE_BANKS }; 720 + s32 iu = (u >> 16) & (SheetWidth - 1); 721 + s32 iv = (v >> 16) & (SheetHeight - 1); 722 + 723 + u8 color = mapping[tic_tilesheet_getpix(&sheet, iu, iv)]; 724 + if (color != TRANSPARENT_COLOR) 725 + setPixel(core, x, y, color); 726 + u += dudxs; 727 + v += dvdxs; 728 + } 729 + } 730 + } 731 + } 732 + } 733 + 734 + void tic_api_textri(tic_mem* memory, float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, bool use_map, u8* colors, s32 count) 735 + { 736 + drawTexturedTriangle((tic_core*)memory, x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, use_map, colors, count); 737 + } 738 + 739 + void tic_api_map(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, s32 sx, s32 sy, u8* colors, s32 count, s32 scale, RemapFunc remap, void* data) 740 + { 741 + drawMap((tic_core*)memory, &memory->ram.map, x, y, width, height, sx, sy, colors, count, scale, remap, data); 742 + } 743 + 744 + void tic_api_mset(tic_mem* memory, s32 x, s32 y, u8 value) 745 + { 746 + if (x < 0 || x >= TIC_MAP_WIDTH || y < 0 || y >= TIC_MAP_HEIGHT) return; 747 + 748 + tic_map* src = &memory->ram.map; 749 + *(src->data + y * TIC_MAP_WIDTH + x) = value; 750 + } 751 + 752 + u8 tic_api_mget(tic_mem* memory, s32 x, s32 y) 753 + { 754 + if (x < 0 || x >= TIC_MAP_WIDTH || y < 0 || y >= TIC_MAP_HEIGHT) return 0; 755 + 756 + const tic_map* src = &memory->ram.map; 757 + return *(src->data + y * TIC_MAP_WIDTH + x); 758 + } 759 + 760 + static inline void setLinePixel(tic_mem* tic, s32 x, s32 y, u8 color) 761 + { 762 + setPixel((tic_core*)tic, x, y, color); 763 + } 764 + 765 + void tic_api_line(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color) 766 + { 767 + ticLine(memory, x0, y0, x1, y1, mapColor(memory, color), setLinePixel); 768 + }
+151
src/core/io.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 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 "api.h" 24 + #include "core.h" 25 + 26 + STATIC_ASSERT(tic80_input, sizeof(tic80_input) == 12); 27 + 28 + static bool isKeyPressed(const tic80_keyboard* input, tic_key key) 29 + { 30 + for (s32 i = 0; i < TIC80_KEY_BUFFER; i++) 31 + if (input->keys[i] == key) 32 + return true; 33 + 34 + return false; 35 + } 36 + 37 + u32 tic_api_btnp(tic_mem* tic, s32 index, s32 hold, s32 period) 38 + { 39 + tic_core* core = (tic_core*)tic; 40 + 41 + if (index < 0) 42 + { 43 + return (~core->state.gamepads.previous.data) & core->memory.ram.input.gamepads.data; 44 + } 45 + else if (hold < 0 || period < 0) 46 + { 47 + return ((~core->state.gamepads.previous.data) & core->memory.ram.input.gamepads.data) & (1 << index); 48 + } 49 + 50 + tic80_gamepads previous; 51 + 52 + previous.data = core->state.gamepads.holds[index] >= hold 53 + ? period && core->state.gamepads.holds[index] % period ? core->state.gamepads.previous.data : 0 54 + : core->state.gamepads.previous.data; 55 + 56 + return ((~previous.data) & core->memory.ram.input.gamepads.data) & (1 << index); 57 + } 58 + 59 + u32 tic_api_btn(tic_mem* tic, s32 index) 60 + { 61 + tic_core* core = (tic_core*)tic; 62 + 63 + if (index < 0) 64 + { 65 + return (~core->state.gamepads.previous.data) & core->memory.ram.input.gamepads.data; 66 + } 67 + else 68 + { 69 + return ((~core->state.gamepads.previous.data) & core->memory.ram.input.gamepads.data) & (1 << index); 70 + } 71 + } 72 + 73 + bool tic_api_key(tic_mem* tic, tic_key key) 74 + { 75 + return key > tic_key_unknown 76 + ? isKeyPressed(&tic->ram.input.keyboard, key) 77 + : tic->ram.input.keyboard.data; 78 + } 79 + 80 + bool tic_api_keyp(tic_mem* tic, tic_key key, s32 hold, s32 period) 81 + { 82 + tic_core* core = (tic_core*)tic; 83 + 84 + if (key > tic_key_unknown) 85 + { 86 + bool prevDown = hold >= 0 && period >= 0 && core->state.keyboard.holds[key] >= hold 87 + ? period && core->state.keyboard.holds[key] % period 88 + ? isKeyPressed(&core->state.keyboard.previous, key) 89 + : false 90 + : isKeyPressed(&core->state.keyboard.previous, key); 91 + 92 + bool down = isKeyPressed(&tic->ram.input.keyboard, key); 93 + 94 + return !prevDown && down; 95 + } 96 + 97 + for (s32 i = 0; i < TIC80_KEY_BUFFER; i++) 98 + { 99 + tic_key key = tic->ram.input.keyboard.keys[i]; 100 + 101 + if (key) 102 + { 103 + bool wasPressed = false; 104 + 105 + for (s32 p = 0; p < TIC80_KEY_BUFFER; p++) 106 + { 107 + if (core->state.keyboard.previous.keys[p] == key) 108 + { 109 + wasPressed = true; 110 + break; 111 + } 112 + } 113 + 114 + if (!wasPressed) 115 + return true; 116 + } 117 + } 118 + 119 + return false; 120 + } 121 + 122 + void tic_api_mouse(tic_mem* memory) {} 123 + 124 + void tic_core_tick_io(tic_mem* memory) 125 + { 126 + tic_core* core = (tic_core*)memory; 127 + 128 + // process gamepad 129 + for (s32 i = 0; i < COUNT_OF(core->state.gamepads.holds); i++) 130 + { 131 + u32 mask = 1 << i; 132 + u32 prevDown = core->state.gamepads.previous.data & mask; 133 + u32 down = memory->ram.input.gamepads.data & mask; 134 + 135 + u32* hold = &core->state.gamepads.holds[i]; 136 + if (prevDown && prevDown == down) (*hold)++; 137 + else *hold = 0; 138 + } 139 + 140 + // process keyboard 141 + for (s32 i = 0; i < tic_keys_count; i++) 142 + { 143 + bool prevDown = isKeyPressed(&core->state.keyboard.previous, i); 144 + bool down = isKeyPressed(&memory->ram.input.keyboard, i); 145 + 146 + u32* hold = &core->state.keyboard.holds[i]; 147 + 148 + if (prevDown && down) (*hold)++; 149 + else *hold = 0; 150 + } 151 + }
+10 -4
src/core/machine.h src/core/core.h
··· 26 26 #include "tools.h" 27 27 #include "blip_buf.h" 28 28 29 + #define CLOCKRATE (255<<13) 30 + 29 31 typedef struct 30 32 { 31 33 s32 time; /* clock time of next delta */ ··· 156 158 u32 synced; 157 159 158 160 bool initialized; 159 - } tic_machine_state_data; 161 + } tic_core_state_data; 160 162 161 163 typedef struct 162 164 { ··· 192 194 193 195 tic_tick_data* data; 194 196 195 - tic_machine_state_data state; 197 + tic_core_state_data state; 196 198 197 199 struct 198 200 { 199 - tic_machine_state_data state; 201 + tic_core_state_data state; 200 202 tic_ram ram; 201 203 u8 input; 202 204 ··· 207 209 } time; 208 210 } pause; 209 211 210 - } tic_machine; 212 + } tic_core; 211 213 212 214 #if defined(TIC_BUILD_WITH_SQUIRREL) 213 215 const tic_script_config* getSquirrelScriptConfig(); ··· 233 235 #if defined(TIC_BUILD_WITH_WREN) 234 236 const tic_script_config* getWrenScriptConfig(); 235 237 #endif 238 + 239 + void tic_core_tick_io(tic_mem* memory); 240 + void tick_core_sound_tick_start(tic_mem* memory); 241 + void tick_core_sound_tick_end(tic_mem* memory);
+532
src/core/sound.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 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 + 24 + #include "api.h" 25 + #include "core.h" 26 + 27 + #include <string.h> 28 + 29 + #define ENVELOPE_FREQ_SCALE 2 30 + #define SECONDS_PER_MINUTE 60 31 + #define NOTES_PER_MUNUTE (TIC80_FRAMERATE / NOTES_PER_BEAT * SECONDS_PER_MINUTE) 32 + #define PIANO_START 8 33 + 34 + static const u16 NoteFreqs[] = { 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1d, 0x1f, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2c, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3e, 0x41, 0x45, 0x49, 0x4e, 0x52, 0x57, 0x5c, 0x62, 0x68, 0x6e, 0x75, 0x7b, 0x83, 0x8b, 0x93, 0x9c, 0xa5, 0xaf, 0xb9, 0xc4, 0xd0, 0xdc, 0xe9, 0xf7, 0x106, 0x115, 0x126, 0x137, 0x14a, 0x15d, 0x172, 0x188, 0x19f, 0x1b8, 0x1d2, 0x1ee, 0x20b, 0x22a, 0x24b, 0x26e, 0x293, 0x2ba, 0x2e4, 0x310, 0x33f, 0x370, 0x3a4, 0x3dc, 0x417, 0x455, 0x497, 0x4dd, 0x527, 0x575, 0x5c8, 0x620, 0x67d, 0x6e0, 0x749, 0x7b8, 0x82d, 0x8a9, 0x92d, 0x9b9, 0xa4d, 0xaea, 0xb90, 0xc40, 0xcfa, 0xdc0, 0xe91, 0xf6f, 0x105a, 0x1153, 0x125b, 0x1372, 0x149a, 0x15d4, 0x1720, 0x1880 }; 35 + STATIC_ASSERT(count_of_freqs, COUNT_OF(NoteFreqs) == NOTES * OCTAVES + PIANO_START); 36 + STATIC_ASSERT(tic_sound_register, sizeof(tic_sound_register) == 16 + 2); 37 + STATIC_ASSERT(tic_sample, sizeof(tic_sample) == 66); 38 + STATIC_ASSERT(tic_track_pattern, sizeof(tic_track_pattern) == 3 * MUSIC_PATTERN_ROWS); 39 + STATIC_ASSERT(tic_track, sizeof(tic_track) == 3 * MUSIC_FRAMES + 3); 40 + STATIC_ASSERT(tic_music_cmd_count, tic_music_cmd_count == 1 << MUSIC_CMD_BITS); 41 + STATIC_ASSERT(tic_sound_state_size, sizeof(tic_sound_state) == 4); 42 + 43 + static inline s32 getTempo(const tic_track* track) { return track->tempo + DEFAULT_TEMPO; } 44 + static inline s32 getSpeed(const tic_track* track) { return track->speed + DEFAULT_SPEED; } 45 + 46 + static s32 tick2row(const tic_track* track, s32 tick) 47 + { 48 + // BPM = tempo * 6 / speed 49 + return tick * getTempo(track) * DEFAULT_SPEED / getSpeed(track) / NOTES_PER_MUNUTE; 50 + } 51 + 52 + static s32 row2tick(const tic_track* track, s32 row) 53 + { 54 + return row * getSpeed(track) * NOTES_PER_MUNUTE / getTempo(track) / DEFAULT_SPEED; 55 + } 56 + 57 + static inline s32 param2val(const tic_track_row* row) 58 + { 59 + return (row->param1 << 4) | row->param2; 60 + } 61 + 62 + static void update_amp(blip_buffer_t* blip, tic_sound_register_data* data, s32 new_amp) 63 + { 64 + s32 delta = new_amp - data->amp; 65 + data->amp += delta; 66 + blip_add_delta(blip, data->time, delta); 67 + } 68 + 69 + static inline s32 freq2period(s32 freq) 70 + { 71 + enum 72 + { 73 + MinPeriodValue = 10, 74 + MaxPeriodValue = 4096, 75 + Rate = CLOCKRATE * ENVELOPE_FREQ_SCALE / WAVE_VALUES 76 + }; 77 + 78 + if (freq == 0) return MaxPeriodValue; 79 + 80 + return CLAMP(Rate / freq - 1, MinPeriodValue, MaxPeriodValue); 81 + } 82 + 83 + static inline s32 getAmp(const tic_sound_register* reg, s32 amp) 84 + { 85 + enum { AmpMax = (u16)-1 / 2 }; 86 + return (amp * AmpMax / MAX_VOLUME) * reg->volume / MAX_VOLUME / TIC_SOUND_CHANNELS; 87 + } 88 + 89 + static void runEnvelope(blip_buffer_t* blip, const tic_sound_register* reg, tic_sound_register_data* data, s32 end_time, u8 volume) 90 + { 91 + s32 period = freq2period(reg->freq * ENVELOPE_FREQ_SCALE); 92 + 93 + for (; data->time < end_time; data->time += period) 94 + { 95 + data->phase = (data->phase + 1) % WAVE_VALUES; 96 + 97 + update_amp(blip, data, getAmp(reg, tic_tool_peek4(reg->waveform.data, data->phase) * volume / MAX_VOLUME)); 98 + } 99 + } 100 + 101 + static void runNoise(blip_buffer_t* blip, const tic_sound_register* reg, tic_sound_register_data* data, s32 end_time, u8 volume) 102 + { 103 + // phase is noise LFSR, which must never be zero 104 + if (data->phase == 0) 105 + data->phase = 1; 106 + 107 + s32 period = freq2period(reg->freq); 108 + 109 + for (; data->time < end_time; data->time += period) 110 + { 111 + data->phase = ((data->phase & 1) * (0b11 << 13)) ^ (data->phase >> 1); 112 + update_amp(blip, data, getAmp(reg, (data->phase & 1) ? volume : 0)); 113 + } 114 + } 115 + 116 + static s32 calcLoopPos(const tic_sound_loop* loop, s32 pos) 117 + { 118 + s32 offset = 0; 119 + 120 + if (loop->size > 0) 121 + { 122 + for (s32 i = 0; i < pos; i++) 123 + { 124 + if (offset < (loop->start + loop->size - 1)) 125 + offset++; 126 + else offset = loop->start; 127 + } 128 + } 129 + else offset = pos >= SFX_TICKS ? SFX_TICKS - 1 : pos; 130 + 131 + return offset; 132 + } 133 + 134 + static void resetSfxPos(tic_channel_data* channel) 135 + { 136 + memset(channel->pos->data, -1, sizeof(tic_sfx_pos)); 137 + channel->tick = -1; 138 + } 139 + 140 + static void sfx(tic_mem* memory, s32 index, s32 note, s32 pitch, tic_channel_data* channel, tic_sound_register* reg, s32 channelIndex) 141 + { 142 + tic_core* core = (tic_core*)memory; 143 + 144 + if (channel->duration > 0) 145 + channel->duration--; 146 + 147 + if (index < 0 || channel->duration == 0) 148 + { 149 + resetSfxPos(channel); 150 + return; 151 + } 152 + 153 + const tic_sample* effect = &memory->ram.sfx.samples.data[index]; 154 + s32 pos = tic_tool_sfx_pos(channel->speed, ++channel->tick); 155 + 156 + for (s32 i = 0; i < sizeof(tic_sfx_pos); i++) 157 + *(channel->pos->data + i) = calcLoopPos(effect->loops + i, pos); 158 + 159 + u8 volume = MAX_VOLUME - effect->data[channel->pos->volume].volume; 160 + 161 + if (volume > 0) 162 + { 163 + s8 arp = effect->data[channel->pos->chord].chord * (effect->reverse ? -1 : 1); 164 + if (arp) note += arp; 165 + 166 + note = CLAMP(note, 0, COUNT_OF(NoteFreqs) - 1); 167 + 168 + reg->freq = NoteFreqs[note] + effect->data[channel->pos->pitch].pitch * (effect->pitch16x ? 16 : 1) + pitch; 169 + reg->volume = volume; 170 + 171 + u8 wave = effect->data[channel->pos->wave].wave; 172 + const tic_waveform* waveform = &memory->ram.sfx.waveforms.items[wave]; 173 + memcpy(reg->waveform.data, waveform->data, sizeof(tic_waveform)); 174 + 175 + tic_tool_poke4(&memory->ram.stereo.data, channelIndex * 2, channel->volume.left * !effect->stereo_left); 176 + tic_tool_poke4(&memory->ram.stereo.data, channelIndex * 2 + 1, channel->volume.right * !effect->stereo_right); 177 + } 178 + } 179 + 180 + static void setChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, tic_channel_data* channel, s32 volumeLeft, s32 volumeRight, s32 speed) 181 + { 182 + tic_core* core = (tic_core*)memory; 183 + 184 + channel->volume.left = volumeLeft; 185 + channel->volume.right = volumeRight; 186 + 187 + if (index >= 0) 188 + { 189 + struct { s8 speed : SFX_SPEED_BITS; } temp = { speed }; 190 + channel->speed = speed == temp.speed ? speed : memory->ram.sfx.samples.data[index].speed; 191 + } 192 + 193 + channel->note = note + octave * NOTES; 194 + channel->duration = duration; 195 + channel->index = index; 196 + 197 + resetSfxPos(channel); 198 + } 199 + 200 + 201 + static void setMusicChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 left, s32 right, s32 channel) 202 + { 203 + tic_core* core = (tic_core*)memory; 204 + setChannelData(memory, index, note, octave, -1, &core->state.music.channels[channel], left, right, SFX_DEF_SPEED); 205 + } 206 + 207 + static void resetMusicChannels(tic_mem* memory) 208 + { 209 + for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 210 + setMusicChannelData(memory, -1, 0, 0, 0, 0, c); 211 + 212 + tic_core* core = (tic_core*)memory; 213 + memset(core->state.music.commands, 0, sizeof core->state.music.commands); 214 + memset(&core->state.music.jump, 0, sizeof(tic_jump_command)); 215 + } 216 + 217 + static void stopMusic(tic_mem* memory) 218 + { 219 + tic_api_music(memory, -1, 0, 0, false, false); 220 + } 221 + 222 + static void processMusic(tic_mem* memory) 223 + { 224 + tic_core* core = (tic_core*)memory; 225 + tic_sound_state* sound_state = &memory->ram.sound_state; 226 + 227 + if (sound_state->flag.music_state == tic_music_stop) return; 228 + 229 + const tic_track* track = &memory->ram.music.tracks.data[sound_state->music.track]; 230 + s32 row = tick2row(track, core->state.music.ticks); 231 + tic_jump_command* jumpCmd = &core->state.music.jump; 232 + 233 + if (row != sound_state->music.row 234 + && jumpCmd->active) 235 + { 236 + sound_state->music.frame = jumpCmd->frame; 237 + sound_state->music.row = jumpCmd->beat * NOTES_PER_BEAT; 238 + core->state.music.ticks = row2tick(track, sound_state->music.row); 239 + memset(jumpCmd, 0, sizeof(tic_jump_command)); 240 + } 241 + 242 + s32 rows = MUSIC_PATTERN_ROWS - track->rows; 243 + if (row >= rows) 244 + { 245 + row = 0; 246 + core->state.music.ticks = 0; 247 + 248 + // If music is in sustain mode, we only reset the channels if the music stopped. 249 + // Otherwise, we reset it on every new frame. 250 + if (sound_state->flag.music_state == tic_music_stop || !sound_state->flag.music_sustain) 251 + { 252 + resetMusicChannels(memory); 253 + 254 + for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 255 + setMusicChannelData(memory, -1, 0, 0, MAX_VOLUME, MAX_VOLUME, c); 256 + } 257 + 258 + if (sound_state->flag.music_state == tic_music_play) 259 + { 260 + sound_state->music.frame++; 261 + 262 + if (sound_state->music.frame >= MUSIC_FRAMES) 263 + { 264 + if (sound_state->flag.music_loop) 265 + sound_state->music.frame = 0; 266 + else 267 + { 268 + stopMusic(memory); 269 + return; 270 + } 271 + } 272 + else 273 + { 274 + s32 val = 0; 275 + for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 276 + val += tic_tool_get_pattern_id(track, sound_state->music.frame, c); 277 + 278 + // empty frame detected 279 + if (!val) 280 + { 281 + if (sound_state->flag.music_loop) 282 + sound_state->music.frame = 0; 283 + else 284 + { 285 + stopMusic(memory); 286 + return; 287 + } 288 + } 289 + } 290 + } 291 + else if (sound_state->flag.music_state == tic_music_play_frame) 292 + { 293 + if (!sound_state->flag.music_loop) 294 + { 295 + stopMusic(memory); 296 + return; 297 + } 298 + } 299 + } 300 + 301 + if (row != sound_state->music.row) 302 + { 303 + sound_state->music.row = row; 304 + 305 + for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 306 + { 307 + s32 patternId = tic_tool_get_pattern_id(track, sound_state->music.frame, c); 308 + if (!patternId) continue; 309 + 310 + const tic_track_pattern* pattern = &memory->ram.music.patterns.data[patternId - PATTERN_START]; 311 + const tic_track_row* trackRow = &pattern->rows[sound_state->music.row]; 312 + tic_channel_data* channel = &core->state.music.channels[c]; 313 + tic_command_data* cmdData = &core->state.music.commands[c]; 314 + 315 + if (trackRow->command == tic_music_cmd_delay) 316 + { 317 + cmdData->delay.row = trackRow; 318 + cmdData->delay.ticks = param2val(trackRow); 319 + trackRow = NULL; 320 + } 321 + 322 + if (cmdData->delay.row && cmdData->delay.ticks == 0) 323 + { 324 + trackRow = cmdData->delay.row; 325 + cmdData->delay.row = NULL; 326 + } 327 + 328 + if (trackRow) 329 + { 330 + // reset commands data 331 + if (trackRow->note) 332 + { 333 + cmdData->slide.tick = 0; 334 + cmdData->slide.note = channel->note; 335 + } 336 + 337 + if (trackRow->note == NoteStop) 338 + setMusicChannelData(memory, -1, 0, 0, channel->volume.left, channel->volume.right, c); 339 + else if (trackRow->note >= NoteStart) 340 + setMusicChannelData(memory, tic_tool_get_track_row_sfx(trackRow), trackRow->note - NoteStart, trackRow->octave, 341 + channel->volume.left, channel->volume.right, c); 342 + 343 + switch (trackRow->command) 344 + { 345 + case tic_music_cmd_volume: 346 + channel->volume.left = trackRow->param1; 347 + channel->volume.right = trackRow->param2; 348 + break; 349 + 350 + case tic_music_cmd_chord: 351 + cmdData->chord.tick = 0; 352 + cmdData->chord.note1 = trackRow->param1; 353 + cmdData->chord.note2 = trackRow->param2; 354 + break; 355 + 356 + case tic_music_cmd_jump: 357 + core->state.music.jump.active = true; 358 + core->state.music.jump.frame = trackRow->param1; 359 + core->state.music.jump.beat = trackRow->param2; 360 + break; 361 + 362 + case tic_music_cmd_vibrato: 363 + cmdData->vibrato.tick = 0; 364 + cmdData->vibrato.period = trackRow->param1; 365 + cmdData->vibrato.depth = trackRow->param2; 366 + break; 367 + 368 + case tic_music_cmd_slide: 369 + cmdData->slide.duration = param2val(trackRow); 370 + break; 371 + 372 + case tic_music_cmd_pitch: 373 + cmdData->finepitch.value = param2val(trackRow) - PITCH_DELTA; 374 + break; 375 + 376 + default: break; 377 + } 378 + } 379 + } 380 + } 381 + 382 + for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i) 383 + { 384 + tic_channel_data* channel = &core->state.music.channels[i]; 385 + tic_command_data* cmdData = &core->state.music.commands[i]; 386 + 387 + if (channel->index >= 0) 388 + { 389 + s32 note = channel->note; 390 + s32 pitch = 0; 391 + 392 + // process chord commmand 393 + { 394 + s32 chord[] = 395 + { 396 + 0, 397 + cmdData->chord.note1, 398 + cmdData->chord.note2 399 + }; 400 + 401 + note += chord[cmdData->chord.tick % (cmdData->chord.note2 == 0 ? 2 : 3)]; 402 + } 403 + 404 + // process vibrato commmand 405 + if (cmdData->vibrato.period && cmdData->vibrato.depth) 406 + { 407 + static const s32 VibData[] = { 0x0, 0x31f1, 0x61f8, 0x8e3a, 0xb505, 0xd4db, 0xec83, 0xfb15, 0x10000, 0xfb15, 0xec83, 0xd4db, 0xb505, 0x8e3a, 0x61f8, 0x31f1, 0x0, 0xffffce0f, 0xffff9e08, 0xffff71c6, 0xffff4afb, 0xffff2b25, 0xffff137d, 0xffff04eb, 0xffff0000, 0xffff04eb, 0xffff137d, 0xffff2b25, 0xffff4afb, 0xffff71c6, 0xffff9e08, 0xffffce0f }; 408 + STATIC_ASSERT(VibData, COUNT_OF(VibData) == 32); 409 + 410 + s32 p = cmdData->vibrato.period << 1; 411 + pitch += (VibData[(cmdData->vibrato.tick % p) * COUNT_OF(VibData) / p] * cmdData->vibrato.depth) >> 16; 412 + } 413 + 414 + // process slide command 415 + if (cmdData->slide.tick < cmdData->slide.duration) 416 + pitch += (NoteFreqs[channel->note] - NoteFreqs[note = cmdData->slide.note]) * cmdData->slide.tick / cmdData->slide.duration; 417 + 418 + pitch += cmdData->finepitch.value; 419 + 420 + sfx(memory, channel->index, note, pitch, channel, &memory->ram.registers[i], i); 421 + } 422 + 423 + ++cmdData->chord.tick; 424 + ++cmdData->vibrato.tick; 425 + ++cmdData->slide.tick; 426 + 427 + if (cmdData->delay.ticks) 428 + cmdData->delay.ticks--; 429 + } 430 + 431 + core->state.music.ticks++; 432 + } 433 + 434 + static void setSfxChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, s32 channel, s32 left, s32 right, s32 speed) 435 + { 436 + tic_core* core = (tic_core*)memory; 437 + setChannelData(memory, index, note, octave, duration, &core->state.sfx.channels[channel], left, right, speed); 438 + } 439 + 440 + static void setMusic(tic_core* core, s32 index, s32 frame, s32 row, bool loop, bool sustain) 441 + { 442 + tic_mem* memory = (tic_mem*)core; 443 + 444 + memory->ram.sound_state.music.track = index; 445 + 446 + if (index < 0) 447 + { 448 + memory->ram.sound_state.flag.music_state = tic_music_stop; 449 + resetMusicChannels(memory); 450 + } 451 + else 452 + { 453 + for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 454 + setMusicChannelData(memory, -1, 0, 0, MAX_VOLUME, MAX_VOLUME, c); 455 + 456 + memory->ram.sound_state.music.row = row; 457 + memory->ram.sound_state.music.frame = frame < 0 ? 0 : frame; 458 + memory->ram.sound_state.flag.music_loop = loop; 459 + memory->ram.sound_state.flag.music_sustain = sustain; 460 + memory->ram.sound_state.flag.music_state = tic_music_play; 461 + 462 + const tic_track* track = &memory->ram.music.tracks.data[index]; 463 + core->state.music.ticks = row >= 0 ? row2tick(track, row) : 0; 464 + } 465 + } 466 + 467 + void tic_api_music(tic_mem* memory, s32 index, s32 frame, s32 row, bool loop, bool sustain) 468 + { 469 + tic_core* core = (tic_core*)memory; 470 + 471 + setMusic(core, index, frame, row, loop, sustain); 472 + 473 + if (index >= 0) 474 + memory->ram.sound_state.flag.music_state = tic_music_play; 475 + } 476 + 477 + void tic_api_sfx(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, s32 channel, s32 volume, s32 speed) 478 + { 479 + tic_core* core = (tic_core*)memory; 480 + setSfxChannelData(memory, index, note, octave, duration, channel, volume, volume, speed); 481 + } 482 + 483 + static void stereo_tick_end(tic_mem* memory, tic_sound_register_data* registers, blip_buffer_t* blip, u8 stereoRight) 484 + { 485 + enum { EndTime = CLOCKRATE / TIC80_FRAMERATE }; 486 + for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i) 487 + { 488 + u8 volume = tic_tool_peek4(&memory->ram.stereo.data, stereoRight + i * 2); 489 + 490 + const tic_sound_register* reg = &memory->ram.registers[i]; 491 + tic_sound_register_data* data = registers + i; 492 + 493 + tic_tool_is_noise(&reg->waveform) 494 + ? runNoise(blip, reg, data, EndTime, volume) 495 + : runEnvelope(blip, reg, data, EndTime, volume); 496 + 497 + data->time -= EndTime; 498 + } 499 + 500 + blip_end_frame(blip, EndTime); 501 + } 502 + 503 + void tick_core_sound_tick_start(tic_mem* memory) 504 + { 505 + tic_core* core = (tic_core*)memory; 506 + 507 + for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i) 508 + memset(&memory->ram.registers[i], 0, sizeof(tic_sound_register)); 509 + 510 + memory->ram.stereo.data = -1; 511 + 512 + processMusic(memory); 513 + 514 + for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i) 515 + { 516 + tic_channel_data* c = &core->state.sfx.channels[i]; 517 + 518 + if (c->index >= 0) 519 + sfx(memory, c->index, c->note, 0, c, &memory->ram.registers[i], i); 520 + } 521 + } 522 + 523 + void tick_core_sound_tick_end(tic_mem* memory) 524 + { 525 + tic_core* core = (tic_core*)memory; 526 + 527 + stereo_tick_end(memory, core->state.registers.left, core->blip.left, 0); 528 + stereo_tick_end(memory, core->state.registers.right, core->blip.right, 1); 529 + 530 + blip_read_samples(core->blip.left, core->memory.samples.buffer, core->samplerate / TIC80_FRAMERATE, TIC_STEREO_CHANNELS); 531 + blip_read_samples(core->blip.right, core->memory.samples.buffer + 1, core->samplerate / TIC80_FRAMERATE, TIC_STEREO_CHANNELS); 532 + }
-2124
src/core/tic.c
··· 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 <assert.h> 24 - #include <string.h> 25 - #include <stdlib.h> 26 - #include <stdio.h> 27 - #include <ctype.h> 28 - #include <stddef.h> 29 - #include <time.h> 30 - 31 - #ifdef _3DS 32 - #include <3ds.h> 33 - #endif 34 - 35 - #include "api.h" 36 - #include "tools.h" 37 - #include "tilesheet.h" 38 - #include "machine.h" 39 - #include "ext/gif.h" 40 - #include "core/cart.h" 41 - 42 - #define CLOCKRATE (255<<13) 43 - #define ENVELOPE_FREQ_SCALE 2 44 - #define SECONDS_PER_MINUTE 60 45 - #define NOTES_PER_MUNUTE (TIC80_FRAMERATE / NOTES_PER_BEAT * SECONDS_PER_MINUTE) 46 - #define PIANO_START 8 47 - #define TRANSPARENT_COLOR 255 48 - 49 - STATIC_ASSERT(tic_bank_bits, TIC_BANK_BITS == 3); 50 - STATIC_ASSERT(tic_map, sizeof(tic_map) < 1024*32); 51 - STATIC_ASSERT(tic_sample, sizeof(tic_sample) == 66); 52 - STATIC_ASSERT(tic_track_pattern, sizeof(tic_track_pattern) == 3*MUSIC_PATTERN_ROWS); 53 - STATIC_ASSERT(tic_track, sizeof(tic_track) == 3*MUSIC_FRAMES+3); 54 - STATIC_ASSERT(tic_vram, sizeof(tic_vram) == TIC_VRAM_SIZE); 55 - STATIC_ASSERT(tic_ram, sizeof(tic_ram) == TIC_RAM_SIZE); 56 - STATIC_ASSERT(tic_sound_register, sizeof(tic_sound_register) == 16+2); 57 - STATIC_ASSERT(tic80_input, sizeof(tic80_input) == 12); 58 - STATIC_ASSERT(tic_music_cmd_count, tic_music_cmd_count == 1 << MUSIC_CMD_BITS); 59 - STATIC_ASSERT(tic_sound_state_size, sizeof(tic_sound_state) == 4); 60 - 61 - static const u16 NoteFreqs[] = {0x10, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1d, 0x1f, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2c, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3e, 0x41, 0x45, 0x49, 0x4e, 0x52, 0x57, 0x5c, 0x62, 0x68, 0x6e, 0x75, 0x7b, 0x83, 0x8b, 0x93, 0x9c, 0xa5, 0xaf, 0xb9, 0xc4, 0xd0, 0xdc, 0xe9, 0xf7, 0x106, 0x115, 0x126, 0x137, 0x14a, 0x15d, 0x172, 0x188, 0x19f, 0x1b8, 0x1d2, 0x1ee, 0x20b, 0x22a, 0x24b, 0x26e, 0x293, 0x2ba, 0x2e4, 0x310, 0x33f, 0x370, 0x3a4, 0x3dc, 0x417, 0x455, 0x497, 0x4dd, 0x527, 0x575, 0x5c8, 0x620, 0x67d, 0x6e0, 0x749, 0x7b8, 0x82d, 0x8a9, 0x92d, 0x9b9, 0xa4d, 0xaea, 0xb90, 0xc40, 0xcfa, 0xdc0, 0xe91, 0xf6f, 0x105a, 0x1153, 0x125b, 0x1372, 0x149a, 0x15d4, 0x1720, 0x1880}; 62 - STATIC_ASSERT(count_of_freqs, COUNT_OF(NoteFreqs) == NOTES*OCTAVES + PIANO_START); 63 - 64 - static inline s32 getTempo(const tic_track* track) { return track->tempo + DEFAULT_TEMPO; } 65 - static inline s32 getSpeed(const tic_track* track) { return track->speed + DEFAULT_SPEED; } 66 - 67 - static s32 tick2row(const tic_track* track, s32 tick) 68 - { 69 - // BPM = tempo * 6 / speed 70 - return tick * getTempo(track) * DEFAULT_SPEED / getSpeed(track) / NOTES_PER_MUNUTE; 71 - } 72 - 73 - static s32 row2tick(const tic_track* track, s32 row) 74 - { 75 - return row * getSpeed(track) * NOTES_PER_MUNUTE / getTempo(track) / DEFAULT_SPEED; 76 - } 77 - 78 - static inline s32 param2val(const tic_track_row* row) 79 - { 80 - return (row->param1 << 4) | row->param2; 81 - } 82 - 83 - static void update_amp(blip_buffer_t* blip, tic_sound_register_data* data, s32 new_amp ) 84 - { 85 - s32 delta = new_amp - data->amp; 86 - data->amp += delta; 87 - blip_add_delta( blip, data->time, delta ); 88 - } 89 - 90 - static inline s32 freq2period(s32 freq) 91 - { 92 - enum 93 - { 94 - MinPeriodValue = 10, 95 - MaxPeriodValue = 4096, 96 - Rate = CLOCKRATE * ENVELOPE_FREQ_SCALE / WAVE_VALUES 97 - }; 98 - 99 - if(freq == 0) return MaxPeriodValue; 100 - 101 - return CLAMP(Rate / freq - 1, MinPeriodValue, MaxPeriodValue); 102 - } 103 - 104 - static inline s32 getAmp(const tic_sound_register* reg, s32 amp) 105 - { 106 - enum{AmpMax = (u16)-1/2}; 107 - return (amp * AmpMax / MAX_VOLUME) * reg->volume / MAX_VOLUME / TIC_SOUND_CHANNELS; 108 - } 109 - 110 - static void runEnvelope(blip_buffer_t* blip, const tic_sound_register* reg, tic_sound_register_data* data, s32 end_time, u8 volume) 111 - { 112 - s32 period = freq2period(reg->freq * ENVELOPE_FREQ_SCALE); 113 - 114 - for ( ; data->time < end_time; data->time += period ) 115 - { 116 - data->phase = (data->phase + 1) % WAVE_VALUES; 117 - 118 - update_amp(blip, data, getAmp(reg, tic_tool_peek4(reg->waveform.data, data->phase) * volume / MAX_VOLUME)); 119 - } 120 - } 121 - 122 - static void runNoise(blip_buffer_t* blip, const tic_sound_register* reg, tic_sound_register_data* data, s32 end_time, u8 volume) 123 - { 124 - // phase is noise LFSR, which must never be zero 125 - if ( data->phase == 0 ) 126 - data->phase = 1; 127 - 128 - s32 period = freq2period(reg->freq); 129 - 130 - for ( ; data->time < end_time; data->time += period ) 131 - { 132 - data->phase = ((data->phase & 1) * (0b11 << 13)) ^ (data->phase >> 1); 133 - update_amp(blip, data, getAmp(reg, (data->phase & 1) ? volume : 0)); 134 - } 135 - } 136 - 137 - static void resetBlitSegment(tic_mem* memory) 138 - { 139 - memory->ram.vram.blit.segment = 2; 140 - } 141 - 142 - static tic_tilesheet getTileSheetFromSegment(tic_mem* memory, u8 segment) 143 - { 144 - u8* src; 145 - switch(segment){ 146 - case 0: 147 - case 1: 148 - src = (u8*) &memory->ram.font.data; break; 149 - default: 150 - src = (u8*) &memory->ram.tiles.data; break; 151 - } 152 - 153 - return getTileSheet(segment, src); 154 - } 155 - 156 - static void resetPalette(tic_mem* memory) 157 - { 158 - static const u8 DefaultMapping[] = {16, 50, 84, 118, 152, 186, 220, 254}; 159 - memcpy(memory->ram.vram.palette.data, memory->cart.bank0.palette.scn.data, sizeof(tic_palette)); 160 - memcpy(memory->ram.vram.mapping, DefaultMapping, sizeof DefaultMapping); 161 - } 162 - 163 - static u8* getPalette(tic_mem* tic, u8* colors, u8 count) 164 - { 165 - static u8 mapping[TIC_PALETTE_SIZE]; 166 - for (s32 i = 0; i < TIC_PALETTE_SIZE; i++) mapping[i] = tic_tool_peek4(tic->ram.vram.mapping, i); 167 - for (s32 i = 0; i < count; i++) mapping[colors[i]] = TRANSPARENT_COLOR; 168 - return mapping; 169 - } 170 - 171 - static inline u8 mapColor(tic_mem* tic, u8 color) 172 - { 173 - return tic_tool_peek4(tic->ram.vram.mapping, color & 0xf); 174 - } 175 - 176 - static void setPixelDma(tic_mem* tic, s32 x, s32 y, u8 color) 177 - { 178 - tic_tool_poke4(tic->ram.vram.screen.data, y * TIC80_WIDTH + x, color); 179 - } 180 - 181 - static inline u32* getOvrAddr(tic_mem* tic, s32 x, s32 y) 182 - { 183 - enum {Top = (TIC80_FULLHEIGHT-TIC80_HEIGHT)/2}; 184 - enum {Left = (TIC80_FULLWIDTH-TIC80_WIDTH)/2}; 185 - 186 - return tic->screen + x + (y << TIC80_FULLWIDTH_BITS) + (Left + Top * TIC80_FULLWIDTH); 187 - } 188 - 189 - static void setPixelOvr(tic_mem* tic, s32 x, s32 y, u8 color) 190 - { 191 - tic_machine* machine = (tic_machine*)tic; 192 - 193 - *getOvrAddr(tic, x, y) = *(machine->state.ovr.raw + color); 194 - } 195 - 196 - static u8 getPixelOvr(tic_mem* tic, s32 x, s32 y) 197 - { 198 - tic_machine* machine = (tic_machine*)tic; 199 - 200 - u32 color = *getOvrAddr(tic, x, y); 201 - u32* pal = machine->state.ovr.raw; 202 - 203 - for(s32 i = 0; i < TIC_PALETTE_SIZE; i++, pal++) 204 - if(*pal == color) 205 - return i; 206 - 207 - return 0; 208 - } 209 - 210 - static u8 getPixelDma(tic_mem* tic, s32 x, s32 y) 211 - { 212 - tic_machine* machine = (tic_machine*)tic; 213 - 214 - return tic_tool_peek4(machine->memory.ram.vram.screen.data, y * TIC80_WIDTH + x); 215 - } 216 - 217 - static void setPixel(tic_machine* machine, s32 x, s32 y, u8 color) 218 - { 219 - if(x < machine->state.clip.l || y < machine->state.clip.t || x >= machine->state.clip.r || y >= machine->state.clip.b) return; 220 - 221 - machine->state.setpix(&machine->memory, x, y, color); 222 - } 223 - 224 - static u8 getPixel(tic_machine* machine, s32 x, s32 y) 225 - { 226 - if(x < 0 || y < 0 || x >= TIC80_WIDTH || y >= TIC80_HEIGHT) return 0; 227 - 228 - return machine->state.getpix(&machine->memory, x, y); 229 - } 230 - 231 - static void drawHLineDma(tic_mem* memory, s32 xl, s32 xr, s32 y, u8 color) 232 - { 233 - color = color << 4 | color; 234 - if (xl >= xr) return; 235 - if (xl & 1) { 236 - tic_tool_poke4(&memory->ram.vram.screen.data, y * TIC80_WIDTH + xl, color); 237 - xl++; 238 - } 239 - s32 count = (xr - xl) >> 1; 240 - u8 *screen = memory->ram.vram.screen.data + ((y * TIC80_WIDTH + xl) >> 1); 241 - for(s32 i = 0; i < count; i++) *screen++ = color; 242 - if (xr & 1) { 243 - tic_tool_poke4(&memory->ram.vram.screen.data, y * TIC80_WIDTH + xr - 1, color); 244 - } 245 - } 246 - 247 - static void drawHLineOvr(tic_mem* tic, s32 x1, s32 x2, s32 y, u8 color) 248 - { 249 - tic_machine* machine = (tic_machine*)tic; 250 - u32 final_color = *(machine->state.ovr.raw + color); 251 - for(s32 x = x1; x < x2; ++x) { 252 - *getOvrAddr(tic, x, y) = final_color; 253 - } 254 - } 255 - 256 - 257 - #define EARLY_CLIP(x, y, width, height) \ 258 - ( \ 259 - (((y)+(height)-1) < machine->state.clip.t) \ 260 - || (((x)+(width)-1) < machine->state.clip.l) \ 261 - || ((y) >= machine->state.clip.b) \ 262 - || ((x) >= machine->state.clip.r) \ 263 - ) 264 - 265 - static void drawHLine(tic_machine* machine, s32 x, s32 y, s32 width, u8 color) 266 - { 267 - if(y < machine->state.clip.t || machine->state.clip.b <= y) return; 268 - 269 - s32 xl = MAX(x, machine->state.clip.l); 270 - s32 xr = MIN(x + width, machine->state.clip.r); 271 - 272 - machine->state.drawhline(&machine->memory, xl, xr, y, color); 273 - } 274 - 275 - static void drawVLine(tic_machine* machine, s32 x, s32 y, s32 height, u8 color) 276 - { 277 - if(x < machine->state.clip.l || machine->state.clip.r <= x) return; 278 - 279 - s32 yl = y < 0 ? 0 : y; 280 - s32 yr = y + height >= TIC80_HEIGHT ? TIC80_HEIGHT : y + height; 281 - 282 - for(s32 i = yl; i < yr; ++i) 283 - setPixel(machine, x, i, color); 284 - } 285 - 286 - static void drawRect(tic_machine* machine, s32 x, s32 y, s32 width, s32 height, u8 color) 287 - { 288 - for(s32 i = y; i < y + height; ++i) 289 - drawHLine(machine, x, i, width, color); 290 - } 291 - 292 - static void drawRectBorder(tic_machine* machine, s32 x, s32 y, s32 width, s32 height, u8 color) 293 - { 294 - drawHLine(machine, x, y, width, color); 295 - drawHLine(machine, x, y + height - 1, width, color); 296 - 297 - drawVLine(machine, x, y, height, color); 298 - drawVLine(machine, x + width - 1, y, height, color); 299 - } 300 - 301 - #define DRAW_TILE_BODY(X, Y) do {\ 302 - for(s32 py=sy; py < ey; py++, y++) \ 303 - { \ 304 - s32 xx = x; \ 305 - for(s32 px=sx; px < ex; px++, xx++) \ 306 - { \ 307 - u8 color = mapping[getTilePixel(tile, (X), (Y))];\ 308 - if(color != TRANSPARENT_COLOR) machine->state.setpix(&machine->memory, xx, y, color); \ 309 - } \ 310 - } \ 311 - } while(0) 312 - 313 - #define REVERT(X) (TIC_SPRITESIZE - 1 - (X)) 314 - 315 - static void drawTile(tic_machine* machine, tic_tileptr* tile, s32 x, s32 y, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 316 - { 317 - u8* mapping = getPalette(&machine->memory, colors, count); 318 - 319 - rotate &= 0b11; 320 - u32 orientation = flip & 0b11; 321 - 322 - if(rotate == tic_90_rotate) orientation ^= 0b001; 323 - else if(rotate == tic_180_rotate) orientation ^= 0b011; 324 - else if(rotate == tic_270_rotate) orientation ^= 0b010; 325 - if (rotate == tic_90_rotate || rotate == tic_270_rotate) orientation |= 0b100; 326 - 327 - if (scale == 1) { 328 - // the most common path 329 - s32 sx, sy, ex, ey; 330 - sx = machine->state.clip.l - x; if (sx < 0) sx = 0; 331 - sy = machine->state.clip.t - y; if (sy < 0) sy = 0; 332 - ex = machine->state.clip.r - x; if (ex > TIC_SPRITESIZE) ex = TIC_SPRITESIZE; 333 - ey = machine->state.clip.b - y; if (ey > TIC_SPRITESIZE) ey = TIC_SPRITESIZE; 334 - y += sy; 335 - x += sx; 336 - switch (orientation) { 337 - case 0b100: DRAW_TILE_BODY(py, px); break; 338 - case 0b110: DRAW_TILE_BODY(REVERT(py), px); break; 339 - case 0b101: DRAW_TILE_BODY(py, REVERT(px)); break; 340 - case 0b111: DRAW_TILE_BODY(REVERT(py), REVERT(px)); break; 341 - case 0b000: DRAW_TILE_BODY(px, py); break; 342 - case 0b010: DRAW_TILE_BODY(px, REVERT(py)); break; 343 - case 0b001: DRAW_TILE_BODY(REVERT(px), py); break; 344 - case 0b011: DRAW_TILE_BODY(REVERT(px), REVERT(py)); break; 345 - default: assert(!"Unknown value of orientation in drawTile"); 346 - } 347 - return; 348 - } 349 - 350 - if (EARLY_CLIP(x, y, TIC_SPRITESIZE * scale, TIC_SPRITESIZE * scale)) return; 351 - 352 - for(s32 py=0; py < TIC_SPRITESIZE; py++, y+=scale) 353 - { 354 - s32 xx = x; 355 - for(s32 px=0; px < TIC_SPRITESIZE; px++, xx+=scale) 356 - { 357 - s32 i; 358 - s32 ix = orientation & 0b001 ? TIC_SPRITESIZE - px - 1: px; 359 - s32 iy = orientation & 0b010 ? TIC_SPRITESIZE - py - 1: py; 360 - if(orientation & 0b100) { 361 - s32 tmp = ix; ix=iy; iy=tmp; 362 - } 363 - u8 color = mapping[getTilePixel(tile, ix, iy)]; 364 - if(color != TRANSPARENT_COLOR) drawRect(machine, xx, y, scale, scale, color); 365 - } 366 - } 367 - } 368 - 369 - #undef DRAW_TILE_BODY 370 - #undef REVERT 371 - 372 - static void drawSprite(tic_machine* machine, s32 index, s32 x, s32 y, s32 w, s32 h, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 373 - { 374 - tic_tilesheet sheet = getTileSheetFromSegment(&machine->memory, machine->memory.ram.vram.blit.segment); 375 - if ( w == 1 && h == 1){ 376 - tic_tileptr tile = getTile(&sheet, index, false); 377 - drawTile(machine, &tile, x, y, colors, count, scale, flip, rotate); 378 - } 379 - else 380 - { 381 - s32 step = TIC_SPRITESIZE * scale; 382 - s32 cols = sheet.segment->sheet_width; 383 - 384 - const tic_flip vert_horz_flip = tic_horz_flip | tic_vert_flip; 385 - 386 - if (EARLY_CLIP(x, y, w * step, h * step)) return; 387 - 388 - for(s32 i = 0; i < w; i++) 389 - { 390 - for(s32 j = 0; j < h; j++) 391 - { 392 - s32 mx = i; 393 - s32 my = j; 394 - 395 - if(flip == tic_horz_flip || flip == vert_horz_flip) mx = w-1-i; 396 - if(flip == tic_vert_flip || flip == vert_horz_flip) my = h-1-j; 397 - 398 - if (rotate == tic_180_rotate) 399 - { 400 - mx = w-1-mx; 401 - my = h-1-my; 402 - } 403 - else if(rotate == tic_90_rotate) 404 - { 405 - if(flip == tic_no_flip || flip == vert_horz_flip) my = h-1-my; 406 - else mx = w-1-mx; 407 - } 408 - else if(rotate == tic_270_rotate) 409 - { 410 - if(flip == tic_no_flip || flip == vert_horz_flip) mx = w-1-mx; 411 - else my = h-1-my; 412 - } 413 - 414 - enum {Cols = TIC_SPRITESHEET_SIZE / TIC_SPRITESIZE}; 415 - 416 - 417 - tic_tileptr tile = getTile(&sheet, index + mx+my*cols, false); 418 - if(rotate==0 || rotate==2) 419 - drawTile(machine, &tile, x+i*step, y+j*step, colors, count, scale, flip, rotate); 420 - else 421 - drawTile(machine, &tile, x+j*step, y+i*step, colors, count, scale, flip, rotate); 422 - } 423 - } 424 - } 425 - } 426 - 427 - static void drawMap(tic_machine* machine, const tic_map* src, s32 x, s32 y, s32 width, s32 height, s32 sx, s32 sy, u8* colors, s32 count, s32 scale, RemapFunc remap, void* data) 428 - { 429 - const s32 size = TIC_SPRITESIZE * scale; 430 - 431 - tic_tilesheet sheet = getTileSheetFromSegment(&machine->memory, machine->memory.ram.vram.blit.segment); 432 - 433 - for(s32 j = y, jj = sy; j < y + height; j++, jj += size) 434 - for(s32 i = x, ii = sx; i < x + width; i++, ii += size) 435 - { 436 - s32 mi = i; 437 - s32 mj = j; 438 - 439 - while(mi < 0) mi += TIC_MAP_WIDTH; 440 - while(mj < 0) mj += TIC_MAP_HEIGHT; 441 - while(mi >= TIC_MAP_WIDTH) mi -= TIC_MAP_WIDTH; 442 - while(mj >= TIC_MAP_HEIGHT) mj -= TIC_MAP_HEIGHT; 443 - 444 - s32 index = mi + mj * TIC_MAP_WIDTH; 445 - RemapResult retile = { *(src->data + index), tic_no_flip, tic_no_rotate }; 446 - 447 - if (remap) 448 - remap(data, mi, mj, &retile); 449 - 450 - tic_tileptr tile = getTile(&sheet, retile.index, true); 451 - drawTile(machine, &tile, ii, jj, colors, count, scale, retile.flip, retile.rotate); 452 - } 453 - } 454 - 455 - static s32 drawChar(tic_machine* machine, tic_tileptr* font_char, s32 x, s32 y, s32 scale, bool fixed, u8* mapping) 456 - { 457 - enum {Size = TIC_SPRITESIZE}; 458 - 459 - s32 j=0, start=0, end=Size; 460 - 461 - if (!fixed) { 462 - for(s32 i=0; i < Size; i++) { 463 - for(j=0; j < Size; j++) 464 - if(mapping[getTilePixel(font_char, i, j)] != TRANSPARENT_COLOR) break; 465 - if (j < Size) break; else start++; 466 - } 467 - for(s32 i=Size-1; i>=start; i--) { 468 - for(j=0; j < Size; j++) 469 - if(mapping[getTilePixel(font_char, i, j)] != TRANSPARENT_COLOR) break; 470 - if (j < Size) break; else end--; 471 - } 472 - } 473 - s32 width = end - start; 474 - 475 - if (EARLY_CLIP(x, y, Size * scale, Size * scale)) return width; 476 - 477 - s32 colStart = start, colStep = 1, rowStart = 0 , rowStep = 1; 478 - 479 - for(s32 i=0, col=colStart, xs = x; i < width; i++, col+=colStep, xs+=scale) 480 - { 481 - for(s32 j = 0, row=rowStart, ys = y; j < Size; j++, row+=rowStep, ys+=scale) 482 - { 483 - u8 color = getTilePixel(font_char, col, row); 484 - if(mapping[color] != TRANSPARENT_COLOR) 485 - drawRect(machine, xs, ys, scale, scale, mapping[color]); 486 - } 487 - } 488 - return width; 489 - } 490 - 491 - static s32 drawText(tic_machine* machine, tic_tilesheet* font_face, const char* text, s32 x, s32 y, s32 width, s32 height, bool fixed, u8* mapping, s32 scale, bool alt) 492 - { 493 - s32 pos = x; 494 - s32 MAX = x; 495 - char sym = 0; 496 - 497 - while((sym = *text++)) 498 - { 499 - if(sym == '\n') 500 - { 501 - if(pos > MAX) 502 - MAX = pos; 503 - 504 - pos = x; 505 - y += height * scale; 506 - } 507 - else { 508 - tic_tileptr font_char = getTile(font_face, alt*TIC_FONT_CHARS/2 + sym, true); 509 - s32 size = drawChar(machine, &font_char, pos, y, scale, fixed, mapping); 510 - pos += ((!fixed && size) ? size + 1 : width) * scale; 511 - } 512 - } 513 - 514 - return pos > MAX ? pos - x : MAX - x; 515 - } 516 - 517 - static void resetSfxPos(tic_channel_data* channel) 518 - { 519 - memset(channel->pos->data, -1, sizeof(tic_sfx_pos)); 520 - channel->tick = -1; 521 - } 522 - 523 - static void setChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, tic_channel_data* channel, s32 volumeLeft, s32 volumeRight, s32 speed) 524 - { 525 - tic_machine* machine = (tic_machine*)memory; 526 - 527 - channel->volume.left = volumeLeft; 528 - channel->volume.right = volumeRight; 529 - 530 - if(index >= 0) 531 - { 532 - struct {s8 speed:SFX_SPEED_BITS;} temp = {speed}; 533 - channel->speed = speed == temp.speed ? speed : memory->ram.sfx.samples.data[index].speed; 534 - } 535 - 536 - channel->note = note + octave * NOTES; 537 - channel->duration = duration; 538 - channel->index = index; 539 - 540 - resetSfxPos(channel); 541 - } 542 - 543 - static void setMusicChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 left, s32 right, s32 channel) 544 - { 545 - tic_machine* machine = (tic_machine*)memory; 546 - setChannelData(memory, index, note, octave, -1, &machine->state.music.channels[channel], left, right, SFX_DEF_SPEED); 547 - } 548 - 549 - static void setSfxChannelData(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, s32 channel, s32 left, s32 right, s32 speed) 550 - { 551 - tic_machine* machine = (tic_machine*)memory; 552 - setChannelData(memory, index, note, octave, duration, &machine->state.sfx.channels[channel], left, right, speed); 553 - } 554 - 555 - static void resetMusicChannels(tic_mem* memory) 556 - { 557 - for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 558 - setMusicChannelData(memory, -1, 0, 0, 0, 0, c); 559 - 560 - tic_machine* machine = (tic_machine*)memory; 561 - memset(machine->state.music.commands, 0, sizeof machine->state.music.commands); 562 - memset(&machine->state.music.jump, 0, sizeof(tic_jump_command)); 563 - } 564 - 565 - static void setMusic(tic_machine* machine, s32 index, s32 frame, s32 row, bool loop, bool sustain) 566 - { 567 - tic_mem* memory = (tic_mem*)machine; 568 - 569 - memory->ram.sound_state.music.track = index; 570 - 571 - if(index < 0) 572 - { 573 - memory->ram.sound_state.flag.music_state = tic_music_stop; 574 - resetMusicChannels(memory); 575 - } 576 - else 577 - { 578 - for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 579 - setMusicChannelData(memory, -1, 0, 0, MAX_VOLUME, MAX_VOLUME, c); 580 - 581 - memory->ram.sound_state.music.row = row; 582 - memory->ram.sound_state.music.frame = frame < 0 ? 0 : frame; 583 - memory->ram.sound_state.flag.music_loop = loop; 584 - memory->ram.sound_state.flag.music_sustain = sustain; 585 - memory->ram.sound_state.flag.music_state = tic_music_play; 586 - 587 - const tic_track* track = &memory->ram.music.tracks.data[index]; 588 - machine->state.music.ticks = row >= 0 ? row2tick(track, row) : 0; 589 - } 590 - } 591 - 592 - void tic_api_music(tic_mem* memory, s32 index, s32 frame, s32 row, bool loop, bool sustain) 593 - { 594 - tic_machine* machine = (tic_machine*)memory; 595 - 596 - setMusic(machine, index, frame, row, loop, sustain); 597 - 598 - if(index >= 0) 599 - memory->ram.sound_state.flag.music_state = tic_music_play; 600 - } 601 - 602 - static void stopMusic(tic_mem* memory) 603 - { 604 - tic_api_music(memory, -1, 0, 0, false, false); 605 - } 606 - 607 - static void soundClear(tic_mem* memory) 608 - { 609 - tic_machine* machine = (tic_machine*)memory; 610 - 611 - for(s32 i = 0; i < TIC_SOUND_CHANNELS; i++) 612 - { 613 - static const tic_channel_data EmptyChannel = 614 - { 615 - .tick = -1, 616 - .pos = NULL, 617 - .index = -1, 618 - .note = 0, 619 - .volume = {0, 0}, 620 - .speed = 0, 621 - .duration = -1, 622 - }; 623 - 624 - memcpy(&machine->state.music.channels[i], &EmptyChannel, sizeof EmptyChannel); 625 - memcpy(&machine->state.sfx.channels[i], &EmptyChannel, sizeof EmptyChannel); 626 - 627 - memset(machine->state.sfx.channels[i].pos = &memory->ram.sfxpos[i], -1, sizeof(tic_sfx_pos)); 628 - memset(machine->state.music.channels[i].pos = &machine->state.music.sfxpos[i], -1, sizeof(tic_sfx_pos)); 629 - } 630 - 631 - memset(&memory->ram.registers, 0, sizeof memory->ram.registers); 632 - memset(memory->samples.buffer, 0, memory->samples.size); 633 - 634 - stopMusic(memory); 635 - } 636 - 637 - static void updateSaveid(tic_mem* memory); 638 - 639 - void tic_api_clip(tic_mem* memory, s32 x, s32 y, s32 width, s32 height) 640 - { 641 - tic_machine* machine = (tic_machine*)memory; 642 - 643 - machine->state.clip.l = x; 644 - machine->state.clip.t = y; 645 - machine->state.clip.r = x + width; 646 - machine->state.clip.b = y + height; 647 - 648 - if(machine->state.clip.l < 0) machine->state.clip.l = 0; 649 - if(machine->state.clip.t < 0) machine->state.clip.t = 0; 650 - if(machine->state.clip.r > TIC80_WIDTH) machine->state.clip.r = TIC80_WIDTH; 651 - if(machine->state.clip.b > TIC80_HEIGHT) machine->state.clip.b = TIC80_HEIGHT; 652 - } 653 - 654 - void tic_api_reset(tic_mem* memory) 655 - { 656 - resetPalette(memory); 657 - resetBlitSegment(memory); 658 - 659 - memset(&memory->ram.vram.vars, 0, sizeof memory->ram.vram.vars); 660 - 661 - tic_api_clip(memory, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); 662 - 663 - soundClear(memory); 664 - 665 - tic_machine* machine = (tic_machine*)memory; 666 - machine->state.initialized = false; 667 - machine->state.scanline = NULL; 668 - machine->state.ovr.callback = NULL; 669 - 670 - machine->state.setpix = setPixelDma; 671 - machine->state.getpix = getPixelDma; 672 - machine->state.drawhline = drawHLineDma; 673 - 674 - updateSaveid(memory); 675 - } 676 - 677 - void tic_core_pause(tic_mem* memory) 678 - { 679 - tic_machine* machine = (tic_machine*)memory; 680 - 681 - memcpy(&machine->pause.state, &machine->state, sizeof(tic_machine_state_data)); 682 - memcpy(&machine->pause.ram, &memory->ram, sizeof(tic_ram)); 683 - machine->pause.input = memory->input.data; 684 - memset(&machine->state.ovr, 0, sizeof machine->state.ovr); 685 - 686 - if (machine->data) 687 - { 688 - machine->pause.time.start = machine->data->start; 689 - machine->pause.time.paused = machine->data->counter(); 690 - } 691 - } 692 - 693 - void tic_core_resume(tic_mem* memory) 694 - { 695 - tic_machine* machine = (tic_machine*)memory; 696 - 697 - if (machine->data) 698 - { 699 - memcpy(&machine->state, &machine->pause.state, sizeof(tic_machine_state_data)); 700 - memcpy(&memory->ram, &machine->pause.ram, sizeof(tic_ram)); 701 - memory->input.data = machine->pause.input; 702 - machine->data->start = machine->pause.time.start + machine->data->counter() - machine->pause.time.paused; 703 - } 704 - } 705 - 706 - void tic_core_close(tic_mem* memory) 707 - { 708 - tic_machine* machine = (tic_machine*)memory; 709 - 710 - machine->state.initialized = false; 711 - 712 - #if defined(TIC_BUILD_WITH_SQUIRREL) 713 - getSquirrelScriptConfig()->close(memory); 714 - #endif 715 - 716 - #if defined(TIC_BUILD_WITH_LUA) 717 - getLuaScriptConfig()->close(memory); 718 - 719 - # if defined(TIC_BUILD_WITH_MOON) 720 - getMoonScriptConfig()->close(memory); 721 - # endif 722 - 723 - # if defined(TIC_BUILD_WITH_FENNEL) 724 - getFennelConfig()->close(memory); 725 - # endif 726 - 727 - #endif /* defined(TIC_BUILD_WITH_LUA) */ 728 - 729 - 730 - #if defined(TIC_BUILD_WITH_JS) 731 - getJsScriptConfig()->close(memory); 732 - #endif 733 - 734 - #if defined(TIC_BUILD_WITH_WREN) 735 - getWrenScriptConfig()->close(memory); 736 - #endif 737 - 738 - blip_delete(machine->blip.left); 739 - blip_delete(machine->blip.right); 740 - 741 - free(memory->samples.buffer); 742 - free(machine); 743 - } 744 - 745 - /////////////////////////////////////////////////////////////////////////////// 746 - // API //////////////////////////////////////////////////////////////////////// 747 - /////////////////////////////////////////////////////////////////////////////// 748 - 749 - void tic_api_rect(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, u8 color) 750 - { 751 - tic_machine* machine = (tic_machine*)memory; 752 - 753 - drawRect(machine, x, y, width, height, mapColor(memory, color)); 754 - } 755 - 756 - void tic_api_cls(tic_mem* memory, u8 color) 757 - { 758 - static const tic_clip_data EmptyClip = {0, 0, TIC80_WIDTH, TIC80_HEIGHT}; 759 - 760 - tic_machine* machine = (tic_machine*)memory; 761 - 762 - if(memcmp(&machine->state.clip, &EmptyClip, sizeof(tic_clip_data)) == 0) 763 - { 764 - color &= 0b00001111; 765 - memset(memory->ram.vram.screen.data, color | (color << TIC_PALETTE_BPP), sizeof(memory->ram.vram.screen.data)); 766 - } 767 - else 768 - { 769 - tic_api_rect(memory, machine->state.clip.l, machine->state.clip.t, machine->state.clip.r - machine->state.clip.l, machine->state.clip.b - machine->state.clip.t, color); 770 - } 771 - } 772 - 773 - s32 tic_api_font(tic_mem* memory, const char* text, s32 x, s32 y, u8 chromakey, s32 w, s32 h, bool fixed, s32 scale, bool alt) 774 - { 775 - u8* mapping = getPalette(memory, &chromakey, 1); 776 - 777 - // Compatibility : flip top and bottom of the spritesheet 778 - // to preserve tic_api_font's default target 779 - u8 segment = memory->ram.vram.blit.segment >> 1; 780 - u8 flipmask = 1; while (segment >>= 1) flipmask<<=1; 781 - 782 - tic_tilesheet font_face = getTileSheetFromSegment(memory, memory->ram.vram.blit.segment ^ flipmask); 783 - return drawText((tic_machine*)memory, &font_face, text, x, y, w, h, fixed, mapping, scale, alt); 784 - } 785 - 786 - s32 tic_api_print(tic_mem* memory, const char* text, s32 x, s32 y, u8 color, bool fixed, s32 scale, bool alt) 787 - { 788 - u8 mapping[] = {255, color}; 789 - tic_tilesheet font_face = getTileSheetFromSegment(memory, 1); 790 - // Compatibility : print uses reduced width for non-fixed space 791 - u8 width = alt ? TIC_ALTFONT_WIDTH : TIC_FONT_WIDTH; 792 - if (!fixed) width -= 2; 793 - return drawText((tic_machine*)memory, &font_face, text, x, y, width, TIC_FONT_HEIGHT, fixed, mapping, scale, alt); 794 - } 795 - 796 - void tic_api_spr(tic_mem* memory, s32 index, s32 x, s32 y, s32 w, s32 h, u8* colors, s32 count, s32 scale, tic_flip flip, tic_rotate rotate) 797 - { 798 - drawSprite((tic_machine*)memory, index, x, y, w, h, colors, count, scale, flip, rotate); 799 - } 800 - 801 - static inline u8* getFlag(tic_mem* memory, s32 index, u8 flag) 802 - { 803 - static u8 stub = 0; 804 - if(index >= TIC_FLAGS || flag >= BITS_IN_BYTE) 805 - return &stub; 806 - 807 - return memory->ram.flags.data + index; 808 - } 809 - 810 - bool tic_api_fget(tic_mem* memory, s32 index, u8 flag) 811 - { 812 - return *getFlag(memory, index, flag) & (1 << flag); 813 - } 814 - 815 - void tic_api_fset(tic_mem* memory, s32 index, u8 flag, bool value) 816 - { 817 - if(value) 818 - *getFlag(memory, index, flag) |= (1 << flag); 819 - else 820 - *getFlag(memory, index, flag) &= ~(1 << flag); 821 - } 822 - 823 - u8 tic_api_pix(tic_mem* memory, s32 x, s32 y, u8 color, bool get) 824 - { 825 - tic_machine* machine = (tic_machine*)memory; 826 - 827 - if(get) return getPixel(machine, x, y); 828 - 829 - setPixel(machine, x, y, mapColor(memory, color)); 830 - return 0; 831 - } 832 - 833 - void tic_api_rectb(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, u8 color) 834 - { 835 - tic_machine* machine = (tic_machine*)memory; 836 - 837 - drawRectBorder(machine, x, y, width, height, mapColor(memory, color)); 838 - } 839 - 840 - static struct 841 - { 842 - s16 Left[TIC80_HEIGHT]; 843 - s16 Right[TIC80_HEIGHT]; 844 - s32 ULeft[TIC80_HEIGHT]; 845 - s32 VLeft[TIC80_HEIGHT]; 846 - } SidesBuffer; 847 - 848 - static void initSidesBuffer() 849 - { 850 - for(s32 i = 0; i < COUNT_OF(SidesBuffer.Left); i++) 851 - SidesBuffer.Left[i] = TIC80_WIDTH, SidesBuffer.Right[i] = -1; 852 - } 853 - 854 - static void setSidePixel(s32 x, s32 y) 855 - { 856 - if(y >= 0 && y < TIC80_HEIGHT) 857 - { 858 - if(x < SidesBuffer.Left[y]) SidesBuffer.Left[y] = x; 859 - if(x > SidesBuffer.Right[y]) SidesBuffer.Right[y] = x; 860 - } 861 - } 862 - 863 - static void setSideTexPixel(s32 x, s32 y, float u, float v) 864 - { 865 - s32 yy = y; 866 - if (yy >= 0 && yy < TIC80_HEIGHT) 867 - { 868 - if (x < SidesBuffer.Left[yy]) 869 - { 870 - SidesBuffer.Left[yy] = x; 871 - SidesBuffer.ULeft[yy] = u*65536.0f; 872 - SidesBuffer.VLeft[yy] = v*65536.0f; 873 - } 874 - if (x > SidesBuffer.Right[yy]) 875 - { 876 - SidesBuffer.Right[yy] = x; 877 - } 878 - } 879 - } 880 - 881 - void tic_api_circ(tic_mem* memory, s32 xm, s32 ym, s32 radius, u8 color) 882 - { 883 - tic_machine* machine = (tic_machine*)memory; 884 - 885 - initSidesBuffer(); 886 - 887 - s32 r = radius; 888 - s32 x = -r, y = 0, err = 2-2*r; 889 - do 890 - { 891 - setSidePixel(xm-x, ym+y); 892 - setSidePixel(xm-y, ym-x); 893 - setSidePixel(xm+x, ym-y); 894 - setSidePixel(xm+y, ym+x); 895 - 896 - r = err; 897 - if (r <= y) err += ++y*2+1; 898 - if (r > x || err > y) err += ++x*2+1; 899 - } while (x < 0); 900 - 901 - s32 yt = MAX(machine->state.clip.t, ym-radius); 902 - s32 yb = MIN(machine->state.clip.b, ym+radius+1); 903 - u8 final_color = mapColor(&machine->memory, color); 904 - for(s32 y = yt; y < yb; y++) { 905 - s32 xl = MAX(SidesBuffer.Left[y], machine->state.clip.l); 906 - s32 xr = MIN(SidesBuffer.Right[y]+1, machine->state.clip.r); 907 - machine->state.drawhline(&machine->memory, xl, xr, y, final_color); 908 - } 909 - } 910 - 911 - void tic_api_circb(tic_mem* memory, s32 xm, s32 ym, s32 radius, u8 color) 912 - { 913 - tic_machine* machine = (tic_machine*)memory; 914 - u8 final_color = mapColor(memory, color); 915 - s32 r = radius; 916 - s32 x = -r, y = 0, err = 2-2*r; 917 - do { 918 - setPixel(machine, xm-x, ym+y, final_color); 919 - setPixel(machine, xm-y, ym-x, final_color); 920 - setPixel(machine, xm+x, ym-y, final_color); 921 - setPixel(machine, xm+y, ym+x, final_color); 922 - r = err; 923 - if (r <= y) err += ++y*2+1; 924 - if (r > x || err > y) err += ++x*2+1; 925 - } while (x < 0); 926 - } 927 - 928 - typedef void(*linePixelFunc)(tic_mem* memory, s32 x, s32 y, u8 color); 929 - static void ticLine(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color, linePixelFunc func) 930 - { 931 - if(y0 > y1) 932 - { 933 - SWAP(x0, x1, s32); 934 - SWAP(y0, y1, s32); 935 - } 936 - 937 - s32 dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; 938 - s32 dy = y1 - y0; 939 - s32 err = (dx > dy ? dx : -dy) / 2, e2; 940 - 941 - for(;;) 942 - { 943 - func(memory, x0, y0, color); 944 - if (x0 == x1 && y0 == y1) break; 945 - e2 = err; 946 - if (e2 >-dx) { err -= dy; x0 += sx; } 947 - if (e2 < dy) { err += dx; y0++; } 948 - } 949 - } 950 - 951 - static void triPixelFunc(tic_mem* memory, s32 x, s32 y, u8 color) 952 - { 953 - setSidePixel(x, y); 954 - } 955 - 956 - void tic_api_tri(tic_mem* memory, s32 x1, s32 y1, s32 x2, s32 y2, s32 x3, s32 y3, u8 color) 957 - { 958 - tic_machine* machine = (tic_machine*)memory; 959 - 960 - initSidesBuffer(); 961 - 962 - ticLine(memory, x1, y1, x2, y2, color, triPixelFunc); 963 - ticLine(memory, x2, y2, x3, y3, color, triPixelFunc); 964 - ticLine(memory, x3, y3, x1, y1, color, triPixelFunc); 965 - 966 - u8 final_color = mapColor(&machine->memory, color); 967 - s32 yt = MAX(machine->state.clip.t, MIN(y1, MIN(y2, y3))); 968 - s32 yb = MIN(machine->state.clip.b, MAX(y1, MAX(y2, y3)) + 1); 969 - 970 - for(s32 y = yt; y < yb; y++) { 971 - s32 xl = MAX(SidesBuffer.Left[y], machine->state.clip.l); 972 - s32 xr = MIN(SidesBuffer.Right[y]+1, machine->state.clip.r); 973 - machine->state.drawhline(&machine->memory, xl, xr, y, final_color); 974 - } 975 - } 976 - 977 - 978 - typedef struct 979 - { 980 - float x, y, u, v; 981 - } TexVert; 982 - 983 - 984 - static void ticTexLine(tic_mem* memory, TexVert *v0, TexVert *v1) 985 - { 986 - TexVert *top = v0; 987 - TexVert *bot = v1; 988 - 989 - if (bot->y < top->y) 990 - { 991 - top = v1; 992 - bot = v0; 993 - } 994 - 995 - float dy = bot->y - top->y; 996 - float step_x = (bot->x - top->x); 997 - float step_u = (bot->u - top->u); 998 - float step_v = (bot->v - top->v); 999 - 1000 - if ((s32)dy != 0) 1001 - { 1002 - step_x /= dy; 1003 - step_u /= dy; 1004 - step_v /= dy; 1005 - } 1006 - 1007 - float x = top->x; 1008 - float y = top->y; 1009 - float u = top->u; 1010 - float v = top->v; 1011 - 1012 - if(y < .0f) 1013 - { 1014 - y = .0f - y; 1015 - 1016 - x += step_x * y; 1017 - u += step_u * y; 1018 - v += step_v * y; 1019 - 1020 - y = .0f; 1021 - } 1022 - 1023 - s32 botY = bot->y; 1024 - if(botY > TIC80_HEIGHT) 1025 - botY = TIC80_HEIGHT; 1026 - 1027 - for (; y <botY; ++y) 1028 - { 1029 - setSideTexPixel(x, y, u, v); 1030 - x += step_x; 1031 - u += step_u; 1032 - v += step_v; 1033 - } 1034 - } 1035 - 1036 - static void drawTexturedTriangle(tic_machine* machine, float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, bool use_map, u8* colors, s32 count) 1037 - { 1038 - tic_mem* memory = &machine->memory; 1039 - u8* mapping = getPalette(memory, colors, count); 1040 - TexVert V0, V1, V2; 1041 - 1042 - const u8* map = memory->ram.map.data; 1043 - tic_tilesheet sheet = getTileSheetFromSegment(memory, memory->ram.vram.blit.segment); 1044 - 1045 - V0.x = x1; V0.y = y1; V0.u = u1; V0.v = v1; 1046 - V1.x = x2; V1.y = y2; V1.u = u2; V1.v = v2; 1047 - V2.x = x3; V2.y = y3; V2.u = u3; V2.v = v3; 1048 - 1049 - // calculate the slope of the surface 1050 - // use floats here 1051 - double denom = (V0.x - V2.x) * (V1.y - V2.y) - (V1.x - V2.x) * (V0.y - V2.y); 1052 - if (denom == 0.0) 1053 - { 1054 - return; 1055 - } 1056 - double id = 1.0 / denom; 1057 - float dudx, dvdx; 1058 - // this is the UV slope across the surface 1059 - dudx = ((V0.u - V2.u) * (V1.y - V2.y) - (V1.u - V2.u) * (V0.y - V2.y)) * id; 1060 - dvdx = ((V0.v - V2.v) * (V1.y - V2.y) - (V1.v - V2.v) * (V0.y - V2.y)) * id; 1061 - // convert to fixed 1062 - s32 dudxs = dudx * 65536.0f; 1063 - s32 dvdxs = dvdx * 65536.0f; 1064 - // fill the buffer 1065 - initSidesBuffer(); 1066 - // parse each line and decide where in the buffer to store them ( left or right ) 1067 - ticTexLine(memory, &V0, &V1); 1068 - ticTexLine(memory, &V1, &V2); 1069 - ticTexLine(memory, &V2, &V0); 1070 - 1071 - for (s32 y = 0; y < TIC80_HEIGHT; y++) 1072 - { 1073 - // if it's backwards skip it 1074 - s32 width = SidesBuffer.Right[y] - SidesBuffer.Left[y]; 1075 - // if it's off top or bottom , skip this line 1076 - if ((y < machine->state.clip.t) || (y > machine->state.clip.b)) 1077 - width = 0; 1078 - if (width > 0) 1079 - { 1080 - s32 u = SidesBuffer.ULeft[y]; 1081 - s32 v = SidesBuffer.VLeft[y]; 1082 - s32 left = SidesBuffer.Left[y]; 1083 - s32 right = SidesBuffer.Right[y]; 1084 - // check right edge, and CLAMP it 1085 - if (right > machine->state.clip.r) 1086 - right = machine->state.clip.r; 1087 - // check left edge and offset UV's if we are off the left 1088 - if (left < machine->state.clip.l) 1089 - { 1090 - s32 dist = machine->state.clip.l - SidesBuffer.Left[y]; 1091 - u += dudxs * dist; 1092 - v += dvdxs * dist; 1093 - left = machine->state.clip.l; 1094 - } 1095 - // are we drawing from the map . ok then at least check before the inner loop 1096 - if (use_map == true) 1097 - { 1098 - for (s32 x = left; x < right; ++x) 1099 - { 1100 - enum { MapWidth = TIC_MAP_WIDTH * TIC_SPRITESIZE, MapHeight = TIC_MAP_HEIGHT * TIC_SPRITESIZE }; 1101 - s32 iu = (u >> 16) % MapWidth; 1102 - s32 iv = (v >> 16) % MapHeight; 1103 - 1104 - while (iu < 0) iu += MapWidth; 1105 - while (iv < 0) iv += MapHeight; 1106 - 1107 - u8 tileindex = map[(iv >> 3) * TIC_MAP_WIDTH + (iu >> 3)]; 1108 - tic_tileptr tile = getTile(&sheet, tileindex, true); 1109 - 1110 - u8 color = mapping[getTilePixel(&tile, iu & 7, iv & 7)]; 1111 - if (color != TRANSPARENT_COLOR) 1112 - setPixel(machine, x, y, color); 1113 - u += dudxs; 1114 - v += dvdxs; 1115 - } 1116 - } 1117 - else 1118 - { 1119 - // direct from tile ram 1120 - for (s32 x = left; x < right; ++x) 1121 - { 1122 - enum{SheetWidth = TIC_SPRITESHEET_SIZE, SheetHeight = TIC_SPRITESHEET_SIZE * TIC_SPRITE_BANKS}; 1123 - s32 iu = (u>>16) & (SheetWidth - 1); 1124 - s32 iv = (v>>16) & (SheetHeight - 1); 1125 - 1126 - u8 color = mapping[getTileSheetPixel(&sheet, iu, iv)]; 1127 - if (color != TRANSPARENT_COLOR) 1128 - setPixel(machine, x, y, color); 1129 - u += dudxs; 1130 - v += dvdxs; 1131 - } 1132 - } 1133 - } 1134 - } 1135 - } 1136 - 1137 - void tic_api_textri(tic_mem* memory, float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, bool use_map, u8* colors, s32 count) 1138 - { 1139 - drawTexturedTriangle((tic_machine*)memory, x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, use_map, colors, count); 1140 - } 1141 - 1142 - void tic_api_map(tic_mem* memory, s32 x, s32 y, s32 width, s32 height, s32 sx, s32 sy, u8* colors, s32 count, s32 scale, RemapFunc remap, void* data) 1143 - { 1144 - drawMap((tic_machine*)memory, &memory->ram.map, x, y, width, height, sx, sy, colors, count, scale, remap, data); 1145 - } 1146 - 1147 - void tic_api_mset(tic_mem* memory, s32 x, s32 y, u8 value) 1148 - { 1149 - if(x < 0 || x >= TIC_MAP_WIDTH || y < 0 || y >= TIC_MAP_HEIGHT) return; 1150 - 1151 - tic_map* src = &memory->ram.map; 1152 - *(src->data + y * TIC_MAP_WIDTH + x) = value; 1153 - } 1154 - 1155 - u8 tic_api_mget(tic_mem* memory, s32 x, s32 y) 1156 - { 1157 - if(x < 0 || x >= TIC_MAP_WIDTH || y < 0 || y >= TIC_MAP_HEIGHT) return 0; 1158 - 1159 - const tic_map* src = &memory->ram.map; 1160 - return *(src->data + y * TIC_MAP_WIDTH + x); 1161 - } 1162 - 1163 - static inline void setLinePixel(tic_mem* tic, s32 x, s32 y, u8 color) 1164 - { 1165 - setPixel((tic_machine*)tic, x, y, color); 1166 - } 1167 - 1168 - void tic_api_line(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color) 1169 - { 1170 - ticLine(memory, x0, y0, x1, y1, mapColor(memory, color), setLinePixel); 1171 - } 1172 - 1173 - static s32 calcLoopPos(const tic_sound_loop* loop, s32 pos) 1174 - { 1175 - s32 offset = 0; 1176 - 1177 - if(loop->size > 0) 1178 - { 1179 - for(s32 i = 0; i < pos; i++) 1180 - { 1181 - if(offset < (loop->start + loop->size-1)) 1182 - offset++; 1183 - else offset = loop->start; 1184 - } 1185 - } 1186 - else offset = pos >= SFX_TICKS ? SFX_TICKS - 1 : pos; 1187 - 1188 - return offset; 1189 - } 1190 - 1191 - static void sfx(tic_mem* memory, s32 index, s32 note, s32 pitch, tic_channel_data* channel, tic_sound_register* reg, s32 channelIndex) 1192 - { 1193 - tic_machine* machine = (tic_machine*)memory; 1194 - 1195 - if(channel->duration > 0) 1196 - channel->duration--; 1197 - 1198 - if(index < 0 || channel->duration == 0) 1199 - { 1200 - resetSfxPos(channel); 1201 - return; 1202 - } 1203 - 1204 - const tic_sample* effect = &memory->ram.sfx.samples.data[index]; 1205 - s32 pos = tic_tool_sfx_pos(channel->speed, ++channel->tick); 1206 - 1207 - for(s32 i = 0; i < sizeof(tic_sfx_pos); i++) 1208 - *(channel->pos->data+i) = calcLoopPos(effect->loops + i, pos); 1209 - 1210 - u8 volume = MAX_VOLUME - effect->data[channel->pos->volume].volume; 1211 - 1212 - if(volume > 0) 1213 - { 1214 - s8 arp = effect->data[channel->pos->chord].chord * (effect->reverse ? -1 : 1); 1215 - if(arp) note += arp; 1216 - 1217 - note = CLAMP(note, 0, COUNT_OF(NoteFreqs)-1); 1218 - 1219 - reg->freq = NoteFreqs[note] + effect->data[channel->pos->pitch].pitch * (effect->pitch16x ? 16 : 1) + pitch; 1220 - reg->volume = volume; 1221 - 1222 - u8 wave = effect->data[channel->pos->wave].wave; 1223 - const tic_waveform* waveform = &memory->ram.sfx.waveforms.items[wave]; 1224 - memcpy(reg->waveform.data, waveform->data, sizeof(tic_waveform)); 1225 - 1226 - tic_tool_poke4(&memory->ram.stereo.data, channelIndex*2, channel->volume.left * !effect->stereo_left); 1227 - tic_tool_poke4(&memory->ram.stereo.data, channelIndex*2+1, channel->volume.right * !effect->stereo_right); 1228 - } 1229 - } 1230 - 1231 - static void processMusic(tic_mem* memory) 1232 - { 1233 - tic_machine* machine = (tic_machine*)memory; 1234 - tic_sound_state* sound_state = &memory->ram.sound_state; 1235 - 1236 - if(sound_state->flag.music_state == tic_music_stop) return; 1237 - 1238 - const tic_track* track = &memory->ram.music.tracks.data[sound_state->music.track]; 1239 - s32 row = tick2row(track, machine->state.music.ticks); 1240 - tic_jump_command* jumpCmd = &machine->state.music.jump; 1241 - 1242 - if (row != sound_state->music.row 1243 - && jumpCmd->active) 1244 - { 1245 - sound_state->music.frame = jumpCmd->frame; 1246 - sound_state->music.row = jumpCmd->beat * NOTES_PER_BEAT; 1247 - machine->state.music.ticks = row2tick(track, sound_state->music.row); 1248 - memset(jumpCmd, 0, sizeof(tic_jump_command)); 1249 - } 1250 - 1251 - s32 rows = MUSIC_PATTERN_ROWS - track->rows; 1252 - if (row >= rows) 1253 - { 1254 - row = 0; 1255 - machine->state.music.ticks = 0; 1256 - 1257 - // If music is in sustain mode, we only reset the channels if the music stopped. 1258 - // Otherwise, we reset it on every new frame. 1259 - if(sound_state->flag.music_state == tic_music_stop || !sound_state->flag.music_sustain) 1260 - { 1261 - resetMusicChannels(memory); 1262 - 1263 - for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 1264 - setMusicChannelData(memory, -1, 0, 0, MAX_VOLUME, MAX_VOLUME, c); 1265 - } 1266 - 1267 - if(sound_state->flag.music_state == tic_music_play) 1268 - { 1269 - sound_state->music.frame++; 1270 - 1271 - if(sound_state->music.frame >= MUSIC_FRAMES) 1272 - { 1273 - if(sound_state->flag.music_loop) 1274 - sound_state->music.frame = 0; 1275 - else 1276 - { 1277 - stopMusic(memory); 1278 - return; 1279 - } 1280 - } 1281 - else 1282 - { 1283 - s32 val = 0; 1284 - for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 1285 - val += tic_tool_get_pattern_id(track, sound_state->music.frame, c); 1286 - 1287 - // empty frame detected 1288 - if(!val) 1289 - { 1290 - if(sound_state->flag.music_loop) 1291 - sound_state->music.frame = 0; 1292 - else 1293 - { 1294 - stopMusic(memory); 1295 - return; 1296 - } 1297 - } 1298 - } 1299 - } 1300 - else if(sound_state->flag.music_state == tic_music_play_frame) 1301 - { 1302 - if(!sound_state->flag.music_loop) 1303 - { 1304 - stopMusic(memory); 1305 - return; 1306 - } 1307 - } 1308 - } 1309 - 1310 - if (row != sound_state->music.row) 1311 - { 1312 - sound_state->music.row = row; 1313 - 1314 - for (s32 c = 0; c < TIC_SOUND_CHANNELS; c++) 1315 - { 1316 - s32 patternId = tic_tool_get_pattern_id(track, sound_state->music.frame, c); 1317 - if (!patternId) continue; 1318 - 1319 - const tic_track_pattern* pattern = &memory->ram.music.patterns.data[patternId - PATTERN_START]; 1320 - const tic_track_row* trackRow = &pattern->rows[sound_state->music.row]; 1321 - tic_channel_data* channel = &machine->state.music.channels[c]; 1322 - tic_command_data* cmdData = &machine->state.music.commands[c]; 1323 - 1324 - if(trackRow->command == tic_music_cmd_delay) 1325 - { 1326 - cmdData->delay.row = trackRow; 1327 - cmdData->delay.ticks = param2val(trackRow); 1328 - trackRow = NULL; 1329 - } 1330 - 1331 - if(cmdData->delay.row && cmdData->delay.ticks == 0) 1332 - { 1333 - trackRow = cmdData->delay.row; 1334 - cmdData->delay.row = NULL; 1335 - } 1336 - 1337 - if(trackRow) 1338 - { 1339 - // reset commands data 1340 - if(trackRow->note) 1341 - { 1342 - cmdData->slide.tick = 0; 1343 - cmdData->slide.note = channel->note; 1344 - } 1345 - 1346 - if(trackRow->note == NoteStop) 1347 - setMusicChannelData(memory, -1, 0, 0, channel->volume.left, channel->volume.right, c); 1348 - else if (trackRow->note >= NoteStart) 1349 - setMusicChannelData(memory, tic_tool_get_track_row_sfx(trackRow), trackRow->note - NoteStart, trackRow->octave, 1350 - channel->volume.left, channel->volume.right, c); 1351 - 1352 - switch(trackRow->command) 1353 - { 1354 - case tic_music_cmd_volume: 1355 - channel->volume.left = trackRow->param1; 1356 - channel->volume.right = trackRow->param2; 1357 - break; 1358 - 1359 - case tic_music_cmd_chord: 1360 - cmdData->chord.tick = 0; 1361 - cmdData->chord.note1 = trackRow->param1; 1362 - cmdData->chord.note2 = trackRow->param2; 1363 - break; 1364 - 1365 - case tic_music_cmd_jump: 1366 - machine->state.music.jump.active = true; 1367 - machine->state.music.jump.frame = trackRow->param1; 1368 - machine->state.music.jump.beat = trackRow->param2; 1369 - break; 1370 - 1371 - case tic_music_cmd_vibrato: 1372 - cmdData->vibrato.tick = 0; 1373 - cmdData->vibrato.period = trackRow->param1; 1374 - cmdData->vibrato.depth = trackRow->param2; 1375 - break; 1376 - 1377 - case tic_music_cmd_slide: 1378 - cmdData->slide.duration = param2val(trackRow); 1379 - break; 1380 - 1381 - case tic_music_cmd_pitch: 1382 - cmdData->finepitch.value = param2val(trackRow) - PITCH_DELTA; 1383 - break; 1384 - 1385 - default: break; 1386 - } 1387 - } 1388 - } 1389 - } 1390 - 1391 - for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i ) 1392 - { 1393 - tic_channel_data* channel = &machine->state.music.channels[i]; 1394 - tic_command_data* cmdData = &machine->state.music.commands[i]; 1395 - 1396 - if(channel->index >= 0) 1397 - { 1398 - s32 note = channel->note; 1399 - s32 pitch = 0; 1400 - 1401 - // process chord commmand 1402 - { 1403 - s32 chord[] = 1404 - { 1405 - 0, 1406 - cmdData->chord.note1, 1407 - cmdData->chord.note2 1408 - }; 1409 - 1410 - note += chord[cmdData->chord.tick % (cmdData->chord.note2 == 0 ? 2 : 3)]; 1411 - } 1412 - 1413 - // process vibrato commmand 1414 - if(cmdData->vibrato.period && cmdData->vibrato.depth) 1415 - { 1416 - static const s32 VibData[] = {0x0, 0x31f1, 0x61f8, 0x8e3a, 0xb505, 0xd4db, 0xec83, 0xfb15, 0x10000, 0xfb15, 0xec83, 0xd4db, 0xb505, 0x8e3a, 0x61f8, 0x31f1, 0x0, 0xffffce0f, 0xffff9e08, 0xffff71c6, 0xffff4afb, 0xffff2b25, 0xffff137d, 0xffff04eb, 0xffff0000, 0xffff04eb, 0xffff137d, 0xffff2b25, 0xffff4afb, 0xffff71c6, 0xffff9e08, 0xffffce0f}; 1417 - STATIC_ASSERT(VibData, COUNT_OF(VibData) == 32); 1418 - 1419 - s32 p = cmdData->vibrato.period << 1; 1420 - pitch += (VibData[(cmdData->vibrato.tick % p) * COUNT_OF(VibData) / p] * cmdData->vibrato.depth) >> 16; 1421 - } 1422 - 1423 - // process slide command 1424 - if(cmdData->slide.tick < cmdData->slide.duration) 1425 - pitch += (NoteFreqs[channel->note] - NoteFreqs[note = cmdData->slide.note]) * cmdData->slide.tick / cmdData->slide.duration; 1426 - 1427 - pitch += cmdData->finepitch.value; 1428 - 1429 - sfx(memory, channel->index, note, pitch, channel, &memory->ram.registers[i], i); 1430 - } 1431 - 1432 - ++cmdData->chord.tick; 1433 - ++cmdData->vibrato.tick; 1434 - ++cmdData->slide.tick; 1435 - 1436 - if(cmdData->delay.ticks) 1437 - cmdData->delay.ticks--; 1438 - } 1439 - 1440 - machine->state.music.ticks++; 1441 - } 1442 - 1443 - static bool isKeyPressed(const tic80_keyboard* input, tic_key key) 1444 - { 1445 - for(s32 i = 0; i < TIC80_KEY_BUFFER; i++) 1446 - if(input->keys[i] == key) 1447 - return true; 1448 - 1449 - return false; 1450 - } 1451 - 1452 - void tic_core_tick_start(tic_mem* memory) 1453 - { 1454 - tic_machine* machine = (tic_machine*)memory; 1455 - 1456 - for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i ) 1457 - memset(&memory->ram.registers[i], 0, sizeof(tic_sound_register)); 1458 - 1459 - memory->ram.stereo.data = -1; 1460 - 1461 - processMusic(memory); 1462 - 1463 - for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i ) 1464 - { 1465 - tic_channel_data* c = &machine->state.sfx.channels[i]; 1466 - 1467 - if(c->index >= 0) 1468 - sfx(memory, c->index, c->note, 0, c, &memory->ram.registers[i], i); 1469 - } 1470 - 1471 - // process gamepad 1472 - for(s32 i = 0; i < COUNT_OF(machine->state.gamepads.holds); i++) 1473 - { 1474 - u32 mask = 1 << i; 1475 - u32 prevDown = machine->state.gamepads.previous.data & mask; 1476 - u32 down = memory->ram.input.gamepads.data & mask; 1477 - 1478 - u32* hold = &machine->state.gamepads.holds[i]; 1479 - if(prevDown && prevDown == down) (*hold)++; 1480 - else *hold = 0; 1481 - } 1482 - 1483 - // process keyboard 1484 - for(s32 i = 0; i < tic_keys_count; i++) 1485 - { 1486 - bool prevDown = isKeyPressed(&machine->state.keyboard.previous, i); 1487 - bool down = isKeyPressed(&memory->ram.input.keyboard, i); 1488 - 1489 - u32* hold = &machine->state.keyboard.holds[i]; 1490 - 1491 - if(prevDown && down) (*hold)++; 1492 - else *hold = 0; 1493 - } 1494 - 1495 - machine->state.setpix = setPixelDma; 1496 - machine->state.getpix = getPixelDma; 1497 - machine->state.synced = 0; 1498 - machine->state.drawhline = drawHLineDma; 1499 - } 1500 - 1501 - static void stereo_tick_end(tic_mem* memory, tic_sound_register_data* registers, blip_buffer_t* blip, u8 stereoRight) 1502 - { 1503 - enum {EndTime = CLOCKRATE / TIC80_FRAMERATE}; 1504 - for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i ) 1505 - { 1506 - u8 volume = tic_tool_peek4(&memory->ram.stereo.data, stereoRight + i*2); 1507 - 1508 - const tic_sound_register* reg = &memory->ram.registers[i]; 1509 - tic_sound_register_data* data = registers + i; 1510 - 1511 - tic_tool_is_noise(&reg->waveform) 1512 - ? runNoise(blip, reg, data, EndTime, volume) 1513 - : runEnvelope(blip, reg, data, EndTime, volume); 1514 - 1515 - data->time -= EndTime; 1516 - } 1517 - 1518 - blip_end_frame(blip, EndTime); 1519 - } 1520 - 1521 - void tic_core_tick_end(tic_mem* memory) 1522 - { 1523 - tic_machine* machine = (tic_machine*)memory; 1524 - tic80_input* input = &machine->memory.ram.input; 1525 - 1526 - machine->state.gamepads.previous.data = input->gamepads.data; 1527 - machine->state.keyboard.previous.data = input->keyboard.data; 1528 - 1529 - stereo_tick_end(memory, machine->state.registers.left, machine->blip.left, 0); 1530 - stereo_tick_end(memory, machine->state.registers.right, machine->blip.right, 1); 1531 - 1532 - blip_read_samples(machine->blip.left, machine->memory.samples.buffer, machine->samplerate / TIC80_FRAMERATE, TIC_STEREO_CHANNELS); 1533 - blip_read_samples(machine->blip.right, machine->memory.samples.buffer + 1, machine->samplerate / TIC80_FRAMERATE, TIC_STEREO_CHANNELS); 1534 - 1535 - machine->state.setpix = setPixelOvr; 1536 - machine->state.getpix = getPixelOvr; 1537 - machine->state.drawhline = drawHLineOvr; 1538 - } 1539 - 1540 - void tic_api_sfx(tic_mem* memory, s32 index, s32 note, s32 octave, s32 duration, s32 channel, s32 volume, s32 speed) 1541 - { 1542 - tic_machine* machine = (tic_machine*)memory; 1543 - setSfxChannelData(memory, index, note, octave, duration, channel, volume, volume, speed); 1544 - } 1545 - 1546 - static void initCover(tic_mem* tic) 1547 - { 1548 - const tic_cover_image* cover = &tic->cart.cover; 1549 - 1550 - if(cover->size) 1551 - { 1552 - gif_image* image = gif_read_data(cover->data, cover->size); 1553 - 1554 - if (image) 1555 - { 1556 - if (image->width == TIC80_WIDTH && image->height == TIC80_HEIGHT) 1557 - { 1558 - enum { Size = TIC80_WIDTH * TIC80_HEIGHT }; 1559 - 1560 - for (s32 i = 0; i < Size; i++) 1561 - { 1562 - const gif_color* c = &image->palette[image->buffer[i]]; 1563 - u8 color = tic_tool_find_closest_color(tic->cart.bank0.palette.scn.colors, c); 1564 - tic_tool_poke4(tic->ram.vram.screen.data, i, color); 1565 - } 1566 - } 1567 - 1568 - gif_close(image); 1569 - } 1570 - } 1571 - } 1572 - 1573 - void tic_api_sync(tic_mem* tic, u32 mask, s32 bank, bool toCart) 1574 - { 1575 - tic_machine* machine = (tic_machine*)tic; 1576 - 1577 - static const struct {s32 bank; s32 ram; s32 size;} Sections[] = 1578 - { 1579 - {offsetof(tic_bank, tiles), offsetof(tic_ram, tiles), sizeof(tic_tiles) }, 1580 - {offsetof(tic_bank, sprites), offsetof(tic_ram, sprites), sizeof(tic_tiles) }, 1581 - {offsetof(tic_bank, map), offsetof(tic_ram, map), sizeof(tic_map) }, 1582 - {offsetof(tic_bank, sfx), offsetof(tic_ram, sfx), sizeof(tic_sfx) }, 1583 - {offsetof(tic_bank, music), offsetof(tic_ram, music), sizeof(tic_music) }, 1584 - {offsetof(tic_bank, palette.scn), offsetof(tic_ram, vram.palette), sizeof(tic_palette) }, 1585 - {offsetof(tic_bank, flags), offsetof(tic_ram, flags), sizeof(tic_flags) }, 1586 - }; 1587 - 1588 - enum{Count = COUNT_OF(Sections), Mask = (1 << Count) - 1}; 1589 - 1590 - if(mask == 0) mask = Mask; 1591 - 1592 - mask &= ~machine->state.synced & Mask; 1593 - 1594 - assert(bank >= 0 && bank < TIC_BANKS); 1595 - 1596 - for(s32 i = 0; i < Count; i++) 1597 - { 1598 - if(mask & (1 << i)) 1599 - toCart 1600 - ? memcpy((u8*)&tic->cart.banks[bank] + Sections[i].bank, (u8*)&tic->ram + Sections[i].ram, Sections[i].size) 1601 - : memcpy((u8*)&tic->ram + Sections[i].ram, (u8*)&tic->cart.banks[bank] + Sections[i].bank, Sections[i].size); 1602 - } 1603 - 1604 - // copy OVR palette 1605 - { 1606 - enum {PaletteIndex = 5}; 1607 - 1608 - if(mask & (1 << PaletteIndex)) 1609 - toCart 1610 - ? memcpy(&tic->cart.banks[bank].palette.ovr, &machine->state.ovr.palette, sizeof(tic_palette)) 1611 - : memcpy(&machine->state.ovr.palette, &tic->cart.banks[bank].palette.ovr, sizeof(tic_palette)); 1612 - } 1613 - 1614 - machine->state.synced |= mask; 1615 - } 1616 - 1617 - static void cart2ram(tic_mem* memory) 1618 - { 1619 - static const u8 Font[] = 1620 - { 1621 - #include "font.inl" 1622 - }; 1623 - 1624 - memcpy(memory->ram.font.data, Font, sizeof Font); 1625 - 1626 - tic_api_sync(memory, 0, 0, false); 1627 - initCover(memory); 1628 - } 1629 - 1630 - static const char* readMetatag(const char* code, const char* tag, const char* comment) 1631 - { 1632 - const char* start = NULL; 1633 - 1634 - { 1635 - static char format[] = "%s %s:"; 1636 - 1637 - char* tagBuffer = malloc(strlen(format) + strlen(tag)); 1638 - 1639 - if(tagBuffer) 1640 - { 1641 - sprintf(tagBuffer, format, comment, tag); 1642 - if((start = strstr(code, tagBuffer))) 1643 - start += strlen(tagBuffer); 1644 - free(tagBuffer); 1645 - } 1646 - } 1647 - 1648 - if(start) 1649 - { 1650 - const char* end = strstr(start, "\n"); 1651 - 1652 - if(end) 1653 - { 1654 - while(*start <= ' ' && start < end) start++; 1655 - while(*(end-1) <= ' ' && end > start) end--; 1656 - 1657 - const s32 size = (s32)(end-start); 1658 - 1659 - char* value = (char*)malloc(size+1); 1660 - 1661 - if(value) 1662 - { 1663 - memset(value, 0, size+1); 1664 - memcpy(value, start, size); 1665 - 1666 - return value; 1667 - } 1668 - } 1669 - } 1670 - 1671 - return NULL; 1672 - } 1673 - 1674 - static bool compareMetatag(const char* code, const char* tag, const char* value, const char* comment) 1675 - { 1676 - bool result = false; 1677 - 1678 - const char* str = readMetatag(code, tag, comment); 1679 - 1680 - if(str) 1681 - { 1682 - result = strcmp(str, value) == 0; 1683 - free((void*)str); 1684 - } 1685 - 1686 - return result; 1687 - } 1688 - 1689 - const tic_script_config* tic_core_script_config(tic_mem* memory) 1690 - { 1691 - const char* code = memory->cart.code.data; 1692 - 1693 - #if defined(TIC_BUILD_WITH_MOON) 1694 - if(compareMetatag(code, "script", "moon", getMoonScriptConfig()->singleComment) || 1695 - compareMetatag(code, "script", "moonscript", getMoonScriptConfig()->singleComment)) 1696 - return getMoonScriptConfig(); 1697 - #endif 1698 - 1699 - #if defined(TIC_BUILD_WITH_FENNEL) 1700 - if(compareMetatag(code, "script", "fennel", getFennelConfig()->singleComment)) 1701 - return getFennelConfig(); 1702 - #endif 1703 - 1704 - #if defined(TIC_BUILD_WITH_JS) 1705 - if(compareMetatag(code, "script", "js", getJsScriptConfig()->singleComment) || 1706 - compareMetatag(code, "script", "javascript", getJsScriptConfig()->singleComment)) 1707 - return getJsScriptConfig(); 1708 - #endif 1709 - 1710 - #if defined(TIC_BUILD_WITH_WREN) 1711 - if(compareMetatag(code, "script", "wren", getWrenScriptConfig()->singleComment)) 1712 - return getWrenScriptConfig(); 1713 - #endif 1714 - 1715 - #if defined(TIC_BUILD_WITH_SQUIRREL) 1716 - if (compareMetatag(code, "script", "squirrel", getSquirrelScriptConfig()->singleComment)) 1717 - return getSquirrelScriptConfig(); 1718 - #endif 1719 - 1720 - #if defined(TIC_BUILD_WITH_LUA) 1721 - return getLuaScriptConfig(); 1722 - #elif defined(TIC_BUILD_WITH_JS) 1723 - return getJsScriptConfig(); 1724 - #elif defined(TIC_BUILD_WITH_WREN) 1725 - return getWrenScriptConfig(); 1726 - #elif defined(TIC_BUILD_WITH_SQUIRREL) 1727 - return getSquirrelScriptConfig(); 1728 - #endif 1729 - } 1730 - 1731 - static void updateSaveid(tic_mem* memory) 1732 - { 1733 - memset(memory->saveid, 0, sizeof memory->saveid); 1734 - const char* saveid = readMetatag(memory->cart.code.data, "saveid", tic_core_script_config(memory)->singleComment); 1735 - if(saveid) 1736 - { 1737 - strncpy(memory->saveid, saveid, TIC_SAVEID_SIZE-1); 1738 - free((void*)saveid); 1739 - } 1740 - } 1741 - 1742 - void tic_core_tick(tic_mem* tic, tic_tick_data* data) 1743 - { 1744 - tic_machine* machine = (tic_machine*)tic; 1745 - 1746 - machine->data = data; 1747 - 1748 - if(!machine->state.initialized) 1749 - { 1750 - const char* code = tic->cart.code.data; 1751 - 1752 - bool done = false; 1753 - const tic_script_config* config = NULL; 1754 - 1755 - if(strlen(code)) 1756 - { 1757 - config = tic_core_script_config(tic); 1758 - cart2ram(tic); 1759 - 1760 - machine->state.synced = 0; 1761 - tic->input.data = 0; 1762 - 1763 - if(compareMetatag(code, "input", "mouse", config->singleComment)) 1764 - tic->input.mouse = 1; 1765 - else if(compareMetatag(code, "input", "gamepad", config->singleComment)) 1766 - tic->input.gamepad = 1; 1767 - else if(compareMetatag(code, "input", "keyboard", config->singleComment)) 1768 - tic->input.keyboard = 1; 1769 - else tic->input.data = -1; // default is all enabled 1770 - 1771 - data->start = data->counter(); 1772 - 1773 - done = config->init(tic, code); 1774 - } 1775 - else 1776 - { 1777 - machine->data->error(machine->data->data, "the code is empty"); 1778 - } 1779 - 1780 - if(done) 1781 - { 1782 - machine->state.tick = config->tick; 1783 - machine->state.scanline = config->scanline; 1784 - machine->state.ovr.callback = config->overline; 1785 - 1786 - machine->state.initialized = true; 1787 - } 1788 - else return; 1789 - } 1790 - 1791 - { 1792 - if(!tic->input.keyboard) 1793 - ZEROMEM(tic->ram.input.keyboard); 1794 - 1795 - if(!tic->input.gamepad) 1796 - ZEROMEM(tic->ram.input.gamepads); 1797 - 1798 - if(!tic->input.mouse) 1799 - ZEROMEM(tic->ram.input.mouse); 1800 - } 1801 - 1802 - machine->state.tick(tic); 1803 - } 1804 - 1805 - double tic_api_time(tic_mem* memory) 1806 - { 1807 - tic_machine* machine = (tic_machine*)memory; 1808 - return (double)((machine->data->counter() - machine->data->start)*1000)/machine->data->freq(); 1809 - } 1810 - 1811 - s32 tic_api_tstamp(tic_mem* memory) 1812 - { 1813 - tic_machine* machine = (tic_machine*)memory; 1814 - return (s32)time(NULL); 1815 - } 1816 - 1817 - u32 tic_api_btnp(tic_mem* tic, s32 index, s32 hold, s32 period) 1818 - { 1819 - tic_machine* machine = (tic_machine*)tic; 1820 - 1821 - if(index < 0) 1822 - { 1823 - return (~machine->state.gamepads.previous.data) & machine->memory.ram.input.gamepads.data; 1824 - } 1825 - else if(hold < 0 || period < 0) 1826 - { 1827 - return ((~machine->state.gamepads.previous.data) & machine->memory.ram.input.gamepads.data) & (1 << index); 1828 - } 1829 - 1830 - tic80_gamepads previous; 1831 - 1832 - previous.data = machine->state.gamepads.holds[index] >= hold 1833 - ? period && machine->state.gamepads.holds[index] % period ? machine->state.gamepads.previous.data : 0 1834 - : machine->state.gamepads.previous.data; 1835 - 1836 - return ((~previous.data) & machine->memory.ram.input.gamepads.data) & (1 << index); 1837 - } 1838 - 1839 - u32 tic_api_btn(tic_mem* tic, s32 index) 1840 - { 1841 - tic_machine* machine = (tic_machine*)tic; 1842 - 1843 - if(index < 0) 1844 - { 1845 - return (~machine->state.gamepads.previous.data) & machine->memory.ram.input.gamepads.data; 1846 - } 1847 - else 1848 - { 1849 - return ((~machine->state.gamepads.previous.data) & machine->memory.ram.input.gamepads.data) & (1 << index); 1850 - } 1851 - } 1852 - 1853 - bool tic_api_key(tic_mem* tic, tic_key key) 1854 - { 1855 - return key > tic_key_unknown 1856 - ? isKeyPressed(&tic->ram.input.keyboard, key) 1857 - : tic->ram.input.keyboard.data; 1858 - } 1859 - 1860 - bool tic_api_keyp(tic_mem* tic, tic_key key, s32 hold, s32 period) 1861 - { 1862 - tic_machine* machine = (tic_machine*)tic; 1863 - 1864 - if(key > tic_key_unknown) 1865 - { 1866 - bool prevDown = hold >= 0 && period >= 0 && machine->state.keyboard.holds[key] >= hold 1867 - ? period && machine->state.keyboard.holds[key] % period 1868 - ? isKeyPressed(&machine->state.keyboard.previous, key) 1869 - : false 1870 - : isKeyPressed(&machine->state.keyboard.previous, key); 1871 - 1872 - bool down = isKeyPressed(&tic->ram.input.keyboard, key); 1873 - 1874 - return !prevDown && down; 1875 - } 1876 - 1877 - for(s32 i = 0; i < TIC80_KEY_BUFFER; i++) 1878 - { 1879 - tic_key key = tic->ram.input.keyboard.keys[i]; 1880 - 1881 - if(key) 1882 - { 1883 - bool wasPressed = false; 1884 - 1885 - for(s32 p = 0; p < TIC80_KEY_BUFFER; p++) 1886 - { 1887 - if(machine->state.keyboard.previous.keys[p] == key) 1888 - { 1889 - wasPressed = true; 1890 - break; 1891 - } 1892 - } 1893 - 1894 - if(!wasPressed) 1895 - return true; 1896 - } 1897 - } 1898 - 1899 - return false; 1900 - } 1901 - 1902 - // copied from SDL2 1903 - static inline void memset4(void *dst, u32 val, u32 dwords) 1904 - { 1905 - #if defined(__GNUC__) && defined(i386) 1906 - s32 u0, u1, u2; 1907 - __asm__ __volatile__ ( 1908 - "cld \n\t" 1909 - "rep ; stosl \n\t" 1910 - : "=&D" (u0), "=&a" (u1), "=&c" (u2) 1911 - : "0" (dst), "1" (val), "2" (dwords) 1912 - : "memory" 1913 - ); 1914 - #else 1915 - u32 _n = (dwords + 3) / 4; 1916 - u32 *_p = (u32*)dst; 1917 - u32 _val = (val); 1918 - if (dwords == 0) 1919 - return; 1920 - switch (dwords % 4) 1921 - { 1922 - case 0: do { *_p++ = _val; 1923 - case 3: *_p++ = _val; 1924 - case 2: *_p++ = _val; 1925 - case 1: *_p++ = _val; 1926 - } while ( --_n ); 1927 - } 1928 - #endif 1929 - } 1930 - 1931 - void tic_core_blit_ex(tic_mem* tic, tic80_pixel_color_format fmt, tic_scanline scanline, tic_overline overline, void* data) 1932 - { 1933 - // init OVR palette 1934 - { 1935 - tic_machine* machine = (tic_machine*)tic; 1936 - 1937 - const tic_palette* ovr = &machine->state.ovr.palette; 1938 - bool ovrEmpty = true; 1939 - for(s32 i = 0; i < sizeof(tic_palette); i++) 1940 - if(ovr->data[i]) 1941 - ovrEmpty = false; 1942 - 1943 - memcpy(machine->state.ovr.raw, tic_tool_palette_blit(ovrEmpty ? &tic->ram.vram.palette : ovr, fmt), sizeof machine->state.ovr.raw); 1944 - } 1945 - 1946 - if(scanline) 1947 - scanline(tic, 0, data); 1948 - 1949 - const u32* pal = tic_tool_palette_blit(&tic->ram.vram.palette, fmt); 1950 - 1951 - enum {Top = (TIC80_FULLHEIGHT-TIC80_HEIGHT)/2, Bottom = Top}; 1952 - enum {Left = (TIC80_FULLWIDTH-TIC80_WIDTH)/2, Right = Left}; 1953 - 1954 - u32* out = tic->screen; 1955 - 1956 - memset4(&out[0 * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH*Top); 1957 - 1958 - u32* rowPtr = out + (Top*TIC80_FULLWIDTH); 1959 - for(s32 r = 0; r < TIC80_HEIGHT; r++, rowPtr += TIC80_FULLWIDTH) 1960 - { 1961 - u32 *colPtr = rowPtr + Left; 1962 - memset4(rowPtr, pal[tic->ram.vram.vars.border], Left); 1963 - 1964 - s32 pos = (r + tic->ram.vram.vars.offset.y + TIC80_HEIGHT) % TIC80_HEIGHT * TIC80_WIDTH >> 1; 1965 - 1966 - u32 x = (-tic->ram.vram.vars.offset.x + TIC80_WIDTH) % TIC80_WIDTH; 1967 - for(s32 c = 0; c < TIC80_WIDTH / 2; c++) 1968 - { 1969 - u8 val = ((u8*)tic->ram.vram.screen.data)[pos + c]; 1970 - *(colPtr + (x++ % TIC80_WIDTH)) = pal[val & 0xf]; 1971 - *(colPtr + (x++ % TIC80_WIDTH)) = pal[val >> 4]; 1972 - } 1973 - 1974 - memset4(rowPtr + (TIC80_FULLWIDTH-Right), pal[tic->ram.vram.vars.border], Right); 1975 - 1976 - if(scanline && (r < TIC80_HEIGHT-1)) 1977 - { 1978 - scanline(tic, r+1, data); 1979 - pal = tic_tool_palette_blit(&tic->ram.vram.palette, fmt); 1980 - } 1981 - } 1982 - 1983 - memset4(&out[(TIC80_FULLHEIGHT-Bottom) * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH*Bottom); 1984 - 1985 - if(overline) 1986 - overline(tic, data); 1987 - 1988 - } 1989 - 1990 - static inline void scanline(tic_mem* memory, s32 row, void* data) 1991 - { 1992 - tic_machine* machine = (tic_machine*)memory; 1993 - 1994 - if(machine->state.initialized) 1995 - machine->state.scanline(memory, row, data); 1996 - } 1997 - 1998 - static inline void overline(tic_mem* memory, void* data) 1999 - { 2000 - tic_machine* machine = (tic_machine*)memory; 2001 - 2002 - if(machine->state.initialized) 2003 - machine->state.ovr.callback(memory, data); 2004 - } 2005 - 2006 - void tic_core_blit(tic_mem* tic, tic80_pixel_color_format fmt) 2007 - { 2008 - tic_core_blit_ex(tic, fmt, scanline, overline, NULL); 2009 - } 2010 - 2011 - u8 tic_api_peek(tic_mem* memory, s32 address) 2012 - { 2013 - if(address >=0 && address < sizeof(tic_ram)) 2014 - return *((u8*)&memory->ram + address); 2015 - 2016 - return 0; 2017 - } 2018 - 2019 - void tic_api_poke(tic_mem* memory, s32 address, u8 value) 2020 - { 2021 - if(address >=0 && address < sizeof(tic_ram)) 2022 - *((u8*)&memory->ram + address) = value; 2023 - } 2024 - 2025 - u8 tic_api_peek4(tic_mem* memory, s32 address) 2026 - { 2027 - if(address >=0 && address < sizeof(tic_ram)*2) 2028 - return tic_tool_peek4((u8*)&memory->ram, address); 2029 - 2030 - return 0; 2031 - } 2032 - 2033 - void tic_api_poke4(tic_mem* memory, s32 address, u8 value) 2034 - { 2035 - if(address >=0 && address < sizeof(tic_ram)*2) 2036 - tic_tool_poke4((u8*)&memory->ram, address, value); 2037 - } 2038 - 2039 - void tic_api_memcpy(tic_mem* memory, s32 dst, s32 src, s32 size) 2040 - { 2041 - s32 bound = sizeof(tic_ram) - size; 2042 - 2043 - if(size >= 0 2044 - && size <= sizeof(tic_ram) 2045 - && dst >= 0 2046 - && src >= 0 2047 - && dst <= bound 2048 - && src <= bound) 2049 - { 2050 - u8* base = (u8*)&memory->ram; 2051 - memcpy(base + dst, base + src, size); 2052 - } 2053 - } 2054 - 2055 - void tic_api_memset(tic_mem* memory, s32 dst, u8 val, s32 size) 2056 - { 2057 - s32 bound = sizeof(tic_ram) - size; 2058 - 2059 - if(size >= 0 2060 - && size <= sizeof(tic_ram) 2061 - && dst >= 0 2062 - && dst <= bound) 2063 - { 2064 - u8* base = (u8*)&memory->ram; 2065 - memset(base + dst, val, size); 2066 - } 2067 - } 2068 - 2069 - void tic_api_trace(tic_mem* memory, const char* text, u8 color) 2070 - { 2071 - tic_machine* machine = (tic_machine*)memory; 2072 - machine->data->trace(machine->data->data, text ? text : "nil", color); 2073 - } 2074 - 2075 - u32 tic_api_pmem(tic_mem* tic, s32 index, u32 value, bool set) 2076 - { 2077 - u32 old = tic->ram.persistent.data[index]; 2078 - 2079 - if(set) 2080 - tic->ram.persistent.data[index] = value; 2081 - 2082 - return old; 2083 - } 2084 - 2085 - void tic_api_exit(tic_mem* tic) 2086 - { 2087 - tic_machine* machine = (tic_machine*)tic; 2088 - machine->data->exit(machine->data->data); 2089 - } 2090 - 2091 - void tic_api_mouse(tic_mem* memory) {} 2092 - 2093 - tic_mem* tic_core_create(s32 samplerate) 2094 - { 2095 - tic_machine* machine = (tic_machine*)malloc(sizeof(tic_machine)); 2096 - memset(machine, 0, sizeof(tic_machine)); 2097 - 2098 - if (machine != (tic_machine*)&machine->memory) 2099 - { 2100 - free(machine); 2101 - return NULL; 2102 - } 2103 - 2104 - machine->memory.screen_format = TIC80_PIXEL_COLOR_RGBA8888; 2105 - machine->samplerate = samplerate; 2106 - #ifdef _3DS 2107 - // To feed texture data directly to the 3DS GPU, linearly allocated memory is required, which is 2108 - // not guaranteed by malloc. 2109 - // Additionally, allocate TIC80_FULLHEIGHT + 1 lines to minimize glitches in linear scaling mode. 2110 - machine->memory.screen = linearAlloc(TIC80_FULLWIDTH * (TIC80_FULLHEIGHT + 1) * sizeof(u32)); 2111 - #endif 2112 - machine->memory.samples.size = samplerate * TIC_STEREO_CHANNELS / TIC80_FRAMERATE * sizeof(s16); 2113 - machine->memory.samples.buffer = malloc(machine->memory.samples.size); 2114 - 2115 - machine->blip.left = blip_new(samplerate / 10); 2116 - machine->blip.right = blip_new(samplerate / 10); 2117 - 2118 - blip_set_rates(machine->blip.left, CLOCKRATE, samplerate); 2119 - blip_set_rates(machine->blip.right, CLOCKRATE, samplerate); 2120 - 2121 - tic_api_reset(&machine->memory); 2122 - 2123 - return &machine->memory; 2124 - }
src/core/tic.h src/tic.h
+1 -1
src/core/tic80.c src/tic.c
··· 26 26 #include <tic80.h> 27 27 #include "api.h" 28 28 #include "tools.h" 29 - #include "core/cart.h" 29 + #include "cart.h" 30 30 31 31 #include "ext/gif.h" 32 32
-93
src/core/tilesheet.c
··· 1 - // MIT License 2 - 3 - // Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com 4 - // Damien de Lemeny @ddelemeny // hello@ddelemeny.me 5 - 6 - // Permission is hereby granted, free of charge, to any person obtaining a copy 7 - // of this software and associated documentation files (the "Software"), to deal 8 - // in the Software without restriction, including without limitation the rights 9 - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 - // copies of the Software, and to permit persons to whom the Software is 11 - // furnished to do so, subject to the following conditions: 12 - 13 - // The above copyright notice and this permission notice shall be included in all 14 - // copies or substantial portions of the Software. 15 - 16 - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 - // SOFTWARE. 23 - 24 - #include "tilesheet.h" 25 - #include "machine.h" 26 - 27 - static const tic_blit_segment segments[] = { 28 - // +page +nb_pages 29 - // | +bank +bank_size 30 - // | | | | +sheet_width 31 - // | | | | | +tile_width 32 - {0, 0, 1, 256, 16, 8, TIC_SPRITESIZE, tic_tool_peek1, tic_tool_poke1}, // system gfx 33 - {0, 0, 1, 256, 16, 8, TIC_SPRITESIZE, tic_tool_peek1, tic_tool_poke1}, // system font 34 - {0, 0, 1, 256, 16, 8, sizeof(tic_tile), tic_tool_peek4, tic_tool_poke4}, // 4bpp p0 bg 35 - {0, 1, 1, 256, 16, 8, sizeof(tic_tile), tic_tool_peek4, tic_tool_poke4}, // 4bpp p0 fg 36 - 37 - {0, 0, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p0 bg 38 - {1, 0, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p1 bg 39 - {0, 1, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p0 fg 40 - {1, 1, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p1 fg 41 - 42 - {0, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p0 bg 43 - {1, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p1 bg 44 - {2, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p2 bg 45 - {3, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p3 bg 46 - {0, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p0 fg 47 - {1, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p1 fg 48 - {2, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p2 fg 49 - {3, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p3 fg 50 - }; 51 - 52 - extern u8 getTileSheetPixel(const tic_tilesheet* sheet, s32 x, s32 y); 53 - extern void setTileSheetPixel(const tic_tilesheet* sheet, s32 x, s32 y, u8 value); 54 - extern u8 getTilePixel(const tic_tileptr* tile, s32 x, s32 y); 55 - extern void setTilePixel(const tic_tileptr* tile, s32 x, s32 y, u8 value); 56 - 57 - tic_tilesheet getTileSheet(u8 segment, u8* ptr) 58 - { 59 - return (tic_tilesheet){&segments[segment], ptr}; 60 - } 61 - 62 - tic_tileptr getTile(const tic_tilesheet* sheet, s32 index, bool local) 63 - { 64 - enum {Cols=16, Size=8}; 65 - const tic_blit_segment* segment = sheet->segment; 66 - 67 - s32 bank, page, iy, ix; 68 - if (local) { 69 - index = index & 255; 70 - bank = segment->bank_orig; 71 - page = segment->page_orig; 72 - div_t ixy = div(index, Cols); 73 - iy = ixy.quot; 74 - ix = ixy.rem; 75 - } 76 - else { 77 - // reindex 78 - div_t ia = div(index, segment->bank_size); // bank, bank_index 79 - div_t ib = div(ia.rem, segment->sheet_width); // yi, bank_xi 80 - div_t ic = div(ib.rem, Cols); // page, xi 81 - bank = (ia.quot + segment->bank_orig) % 2; 82 - page = (ic.quot + segment->page_orig) % segment->nb_pages; 83 - iy = ib.quot % Cols; 84 - ix = ic.rem; 85 - } 86 - 87 - div_t xdiv = div(ix, segment->nb_pages); // xbuffer, xoffset 88 - u32 ptr_offset = ( bank * Cols + iy ) * Cols + page * Cols / segment->nb_pages + xdiv.quot; 89 - u8* ptr = sheet->ptr + segment->ptr_size * ptr_offset; 90 - u32 offset = (xdiv.rem * Size); 91 - 92 - return (tic_tileptr){segment, offset, ptr}; 93 - }
+6 -7
src/core/tilesheet.h src/tilesheet.h
··· 23 23 24 24 #pragma once 25 25 26 - #include <stdlib.h> 27 26 #include "tools.h" 28 27 29 28 typedef struct ··· 52 51 u8* ptr; 53 52 } tic_tileptr; 54 53 55 - tic_tilesheet getTileSheet(u8 segment, u8* ptr); 56 - tic_tileptr getTile(const tic_tilesheet* sheet, s32 index, bool local); 54 + tic_tilesheet tic_tilesheet_get(u8 segment, u8* ptr); 55 + tic_tileptr tic_tilesheet_gettile(const tic_tilesheet* sheet, s32 index, bool local); 57 56 58 - inline u8 getTileSheetPixel(const tic_tilesheet* sheet, s32 x, s32 y) 57 + inline u8 tic_tilesheet_getpix(const tic_tilesheet* sheet, s32 x, s32 y) 59 58 { 60 59 // tile coord 61 60 u16 tile_index = ((y >> 3) << 4 ) + (x / sheet->segment->tile_width); ··· 64 63 return sheet->segment->peek(sheet->ptr+tile_index * sheet->segment->ptr_size, pix_addr); 65 64 } 66 65 67 - inline void setTileSheetPixel(const tic_tilesheet* sheet, s32 x, s32 y, u8 value) 66 + inline void tic_tilesheet_setpix(const tic_tilesheet* sheet, s32 x, s32 y, u8 value) 68 67 { 69 68 // tile coord 70 69 u16 tile_index = ((y >> 3) << 4 ) + (x / sheet->segment->tile_width); ··· 73 72 sheet->segment->poke(sheet->ptr + tile_index * sheet->segment->ptr_size, pix_addr, value); 74 73 } 75 74 76 - inline u8 getTilePixel(const tic_tileptr* tile, s32 x, s32 y) 75 + inline u8 tic_tilesheet_gettilepix(const tic_tileptr* tile, s32 x, s32 y) 77 76 { 78 77 u32 addr = tile->offset + x + (y * tile->segment->tile_width); 79 78 return tile->segment->peek(tile->ptr, addr); 80 79 } 81 80 82 - inline void setTilePixel(const tic_tileptr* tile, s32 x, s32 y, u8 value) 81 + inline void tic_tilesheet_settilepix(const tic_tileptr* tile, s32 x, s32 y, u8 value) 83 82 { 84 83 u32 addr = tile->offset + x + (y * tile->segment->tile_width); 85 84 tile->segment->poke(tile->ptr, addr, value);
+1 -1
src/ext/net.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "system.h" 25 + #include "studio/system.h" 26 26 27 27 typedef struct Net Net; 28 28
+1 -1
src/player/sokol.c
··· 1 - #include "system/sokol.h" 1 + #include "system/sokol/sokol.h" 2 2 3 3 #include <stdio.h> 4 4 #include <stdlib.h>
src/studio/code.c src/studio/editors/code.c
+1 -1
src/studio/code.h src/studio/editors/code.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Code Code; 28 28
+1 -1
src/studio/config.c
··· 22 22 23 23 #include "config.h" 24 24 #include "fs.h" 25 - #include "core/cart.h" 25 + #include "cart.h" 26 26 27 27 #include <lua.h> 28 28 #include <lauxlib.h>
+2 -2
src/studio/console.c src/studio/screens/console.c
··· 21 21 // SOFTWARE. 22 22 23 23 #include "console.h" 24 - #include "fs.h" 25 - #include "config.h" 24 + #include "studio/fs.h" 25 + #include "studio/config.h" 26 26 #include "ext/gif.h" 27 27 #include "ext/file_dialog.h" 28 28 #include "studio/project.h"
+1 -1
src/studio/console.h src/studio/screens/console.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef enum 28 28 {
src/studio/dialog.c src/studio/screens/dialog.c
+1 -1
src/studio/dialog.h src/studio/screens/dialog.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Dialog Dialog; 28 28
src/studio/map.c src/studio/editors/map.c
+1 -1
src/studio/map.h src/studio/editors/map.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Map Map; 28 28
+1 -1
src/studio/menu.c src/studio/screens/menu.c
··· 21 21 // SOFTWARE. 22 22 23 23 #include "menu.h" 24 - #include "fs.h" 24 + #include "studio/fs.h" 25 25 26 26 #define DIALOG_WIDTH (TIC80_WIDTH/2) 27 27 #define DIALOG_HEIGHT (TIC80_HEIGHT/2)
+1 -1
src/studio/menu.h src/studio/screens/menu.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Menu Menu; 28 28
src/studio/music.c src/studio/editors/music.c
+1 -1
src/studio/music.h src/studio/editors/music.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Music Music; 28 28
+1 -1
src/studio/project.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "core/cart.h" 25 + #include "cart.h" 26 26 27 27 #define PROJECT_LUA_EXT ".lua" 28 28 #define PROJECT_MOON_EXT ".moon"
+1 -1
src/studio/run.c src/studio/screens/run.c
··· 22 22 23 23 #include "run.h" 24 24 #include "console.h" 25 - #include "fs.h" 25 + #include "studio/fs.h" 26 26 #include "ext/md5.h" 27 27 #include <time.h> 28 28
+1 -1
src/studio/run.h src/studio/screens/run.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Run Run; 28 28
src/studio/sfx.c src/studio/editors/sfx.c
+1 -1
src/studio/sfx.h src/studio/editors/sfx.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Sfx Sfx; 28 28
+3 -3
src/studio/sprite.c src/studio/editors/sprite.c
··· 95 95 96 96 static u8 getSheetPixel(Sprite* sprite, s32 x, s32 y) 97 97 { 98 - return getTileSheetPixel(&sprite->sheet, x, y); 98 + return tic_tilesheet_getpix(&sprite->sheet, x, y); 99 99 } 100 100 101 101 static void setSheetPixel(Sprite* sprite, s32 x, s32 y, u8 color) 102 102 { 103 - setTileSheetPixel(&sprite->sheet, x, y, color); 103 + tic_tilesheet_setpix(&sprite->sheet, x, y, color); 104 104 } 105 105 106 106 static s32 getIndexPosX(Sprite* sprite) ··· 2046 2046 u8 page = sprite->page; 2047 2047 u8 nbPages = sprite->nbPages; 2048 2048 u8* src = (u8*)sprite->src; 2049 - sprite->sheet = getTileSheet((( nbPages + page) << 1) + sprite->bank, src); 2049 + sprite->sheet = tic_tilesheet_get((( nbPages + page) << 1) + sprite->bank, src); 2050 2050 } 2051 2051 2052 2052 void initSprite(Sprite* sprite, tic_mem* tic, tic_tiles* src)
+2 -2
src/studio/sprite.h src/studio/editors/sprite.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 26 - #include "core/tilesheet.h" 25 + #include "studio/studio.h" 26 + #include "tilesheet.h" 27 27 28 28 typedef struct Sprite Sprite; 29 29
src/studio/start.c src/studio/screens/start.c
+1 -1
src/studio/start.h src/studio/screens/start.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Start Start; 28 28
+13 -13
src/studio/studio.c
··· 22 22 23 23 #include "studio.h" 24 24 25 - #include "start.h" 26 - #include "console.h" 27 - #include "run.h" 28 - #include "sprite.h" 29 - #include "map.h" 30 - #include "world.h" 31 - #include "sfx.h" 32 - #include "music.h" 25 + #include "editors/code.h" 26 + #include "editors/sprite.h" 27 + #include "editors/map.h" 28 + #include "editors/world.h" 29 + #include "editors/sfx.h" 30 + #include "editors/music.h" 31 + #include "screens/start.h" 32 + #include "screens/console.h" 33 + #include "screens/run.h" 34 + #include "screens/menu.h" 35 + #include "screens/surf.h" 36 + #include "screens/dialog.h" 33 37 #include "ext/history.h" 34 38 #include "config.h" 35 - #include "code.h" 36 - #include "dialog.h" 37 - #include "menu.h" 38 - #include "surf.h" 39 - #include "studio/project.h" 39 + #include "project.h" 40 40 41 41 #include "fs.h" 42 42
+1 -1
src/studio/studio.h
··· 28 28 #include <stdlib.h> 29 29 #include <stddef.h> 30 30 31 - #include "core/tic.h" 31 + #include "tic.h" 32 32 #include "api.h" 33 33 #include "defines.h" 34 34 #include "tools.h"
+1 -1
src/studio/surf.c src/studio/screens/surf.c
··· 21 21 // SOFTWARE. 22 22 23 23 #include "surf.h" 24 - #include "fs.h" 24 + #include "studio/fs.h" 25 25 #include "console.h" 26 26 #include "studio/project.h" 27 27
+1 -1
src/studio/surf.h src/studio/screens/surf.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 27 27 typedef struct Surf Surf; 28 28
src/studio/world.c src/studio/editors/world.c
+1 -1
src/studio/world.h src/studio/editors/world.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "studio.h" 25 + #include "studio/studio.h" 26 26 #include "map.h" 27 27 28 28 typedef struct World World;
src/system.h src/studio/system.h
src/system/keycodes.inl src/system/sdl/keycodes.inl
+2 -2
src/system/libretro/tic80_libretro.c
··· 4 4 #include <stdarg.h> 5 5 #include <string.h> 6 6 #include <math.h> 7 - #include "core/tic.h" 7 + #include "tic.h" 8 8 #include "libretro-common/include/libretro.h" 9 9 #include "libretro_core_options.h" 10 10 #include "api.h" ··· 16 16 * - TIC_NAME 17 17 * - TIC_VERSION_LABEL 18 18 */ 19 - #include "../../system.h" 19 + #include "studio/system.h" 20 20 21 21 // The maximum amount of inputs (2, 3 or 4) 22 22 #define TIC_MAXPLAYERS 4
+1 -1
src/system/n3ds/keyboard.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "core/tic.h" 25 + #include "tic.h" 26 26 #include "api.h" 27 27 28 28 #include <3ds.h>
+1 -1
src/system/n3ds/net_httpc.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "core/tic.h" 25 + #include "tic.h" 26 26 #include "api.h" 27 27 28 28 #include <3ds.h>
+1 -1
src/system/sdlgpu.c src/system/sdl/sdlgpu.c
··· 20 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 21 // SOFTWARE. 22 22 23 - #include "system.h" 23 + #include "studio/system.h" 24 24 #include "tools.h" 25 25 #include "ext/net.h" 26 26
+443 -443
src/system/sokol.c src/system/sokol/sokol.c
··· 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 <stdio.h> 24 - #include <stdlib.h> 25 - #include <time.h> 26 - #include <limits.h> 27 - 28 - #include "system.h" 29 - #include "system/sokol.h" 30 - #include "net.h" 31 - 32 - static struct 33 - { 34 - Studio* studio; 35 - 36 - struct 37 - { 38 - bool state[tic_keys_count]; 39 - } keyboard; 40 - 41 - struct 42 - { 43 - saudio_desc desc; 44 - float* samples; 45 - } audio; 46 - 47 - char* clipboard; 48 - 49 - Net* net; 50 - 51 - } platform; 52 - 53 - static void setClipboardText(const char* text) 54 - { 55 - if(platform.clipboard) 56 - { 57 - free(platform.clipboard); 58 - platform.clipboard = NULL; 59 - } 60 - 61 - platform.clipboard = strdup(text); 62 - } 63 - 64 - static bool hasClipboardText() 65 - { 66 - return platform.clipboard != NULL; 67 - } 68 - 69 - static char* getClipboardText() 70 - { 71 - return platform.clipboard ? strdup(platform.clipboard) : NULL; 72 - } 73 - 74 - static void freeClipboardText(const char* text) 75 - { 76 - free((void*)text); 77 - } 78 - 79 - static u64 getPerformanceCounter() 80 - { 81 - return stm_now(); 82 - } 83 - 84 - static u64 getPerformanceFrequency() 85 - { 86 - return 1000000000; 87 - } 88 - 89 - static void* httpGetSync(const char* url, s32* size) 90 - { 91 - return netGetSync(platform.net, url, size); 92 - } 93 - 94 - static void httpGet(const char* url, HttpGetCallback callback, void* calldata) 95 - { 96 - return netGet(platform.net, url, callback, calldata); 97 - } 98 - 99 - static void goFullscreen() 100 - { 101 - } 102 - 103 - static void showMessageBox(const char* title, const char* message) 104 - { 105 - } 106 - 107 - static void setWindowTitle(const char* title) 108 - { 109 - } 110 - 111 - static void openSystemPath(const char* path) 112 - { 113 - 114 - } 115 - 116 - static void preseed() 117 - { 118 - #if defined(__TIC_MACOSX__) 119 - srandom(time(NULL)); 120 - random(); 121 - #else 122 - srand(time(NULL)); 123 - rand(); 124 - #endif 125 - } 126 - 127 - static void pollEvent() 128 - { 129 - 130 - } 131 - 132 - static void updateConfig() 133 - { 134 - 135 - } 136 - 137 - static System systemInterface = 138 - { 139 - .setClipboardText = setClipboardText, 140 - .hasClipboardText = hasClipboardText, 141 - .getClipboardText = getClipboardText, 142 - .freeClipboardText = freeClipboardText, 143 - 144 - .getPerformanceCounter = getPerformanceCounter, 145 - .getPerformanceFrequency = getPerformanceFrequency, 146 - 147 - .httpGetSync = httpGetSync, 148 - .httpGet = httpGet, 149 - 150 - .fileDialogLoad = file_dialog_load, 151 - .fileDialogSave = file_dialog_save, 152 - 153 - .goFullscreen = goFullscreen, 154 - .showMessageBox = showMessageBox, 155 - .setWindowTitle = setWindowTitle, 156 - 157 - .openSystemPath = openSystemPath, 158 - .preseed = preseed, 159 - .poll = pollEvent, 160 - .updateConfig = updateConfig, 161 - }; 162 - 163 - static void app_init(void) 164 - { 165 - sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1, false, true); 166 - 167 - stm_setup(); 168 - 169 - platform.audio.samples = calloc(sizeof platform.audio.samples[0], saudio_sample_rate() / TIC80_FRAMERATE * TIC_STEREO_CHANNELS); 170 - } 171 - 172 - static void handleKeyboard() 173 - { 174 - tic_mem* tic = platform.studio->tic; 175 - 176 - tic80_input* input = &tic->ram.input; 177 - input->keyboard.data = 0; 178 - 179 - enum{BufSize = COUNT_OF(input->keyboard.keys)}; 180 - 181 - for(s32 i = 0, c = 0; i < COUNT_OF(platform.keyboard.state) && c < BufSize; i++) 182 - if(platform.keyboard.state[i]) 183 - input->keyboard.keys[c++] = i; 184 - } 185 - 186 - static void app_frame(void) 187 - { 188 - if(platform.studio->quit) exit(0); 189 - 190 - netTick(platform.net); 191 - 192 - tic_mem* tic = platform.studio->tic; 193 - tic80_input* input = &tic->ram.input; 194 - 195 - input->gamepads.data = 0; 196 - handleKeyboard(); 197 - platform.studio->tick(input); 198 - 199 - sokol_gfx_draw(platform.studio->tic->screen); 200 - 201 - s32 count = tic->samples.size / sizeof tic->samples.buffer[0]; 202 - for(s32 i = 0; i < count; i++) 203 - platform.audio.samples[i] = (float)tic->samples.buffer[i] / SHRT_MAX; 204 - 205 - saudio_push(platform.audio.samples, count / 2); 206 - 207 - input->mouse.scrollx = input->mouse.scrolly = 0; 208 - } 209 - 210 - static void handleKeydown(sapp_keycode keycode, bool down) 211 - { 212 - static const tic_keycode KeyboardCodes[] = 213 - { 214 - [SAPP_KEYCODE_INVALID] = tic_key_unknown, 215 - [SAPP_KEYCODE_SPACE] = tic_key_space, 216 - [SAPP_KEYCODE_APOSTROPHE] = tic_key_apostrophe, 217 - [SAPP_KEYCODE_COMMA] = tic_key_comma, 218 - [SAPP_KEYCODE_MINUS] = tic_key_minus, 219 - [SAPP_KEYCODE_PERIOD] = tic_key_period, 220 - [SAPP_KEYCODE_SLASH] = tic_key_slash, 221 - [SAPP_KEYCODE_0] = tic_key_0, 222 - [SAPP_KEYCODE_1] = tic_key_1, 223 - [SAPP_KEYCODE_2] = tic_key_2, 224 - [SAPP_KEYCODE_3] = tic_key_3, 225 - [SAPP_KEYCODE_4] = tic_key_4, 226 - [SAPP_KEYCODE_5] = tic_key_5, 227 - [SAPP_KEYCODE_6] = tic_key_6, 228 - [SAPP_KEYCODE_7] = tic_key_7, 229 - [SAPP_KEYCODE_8] = tic_key_8, 230 - [SAPP_KEYCODE_9] = tic_key_9, 231 - [SAPP_KEYCODE_SEMICOLON] = tic_key_semicolon, 232 - [SAPP_KEYCODE_EQUAL] = tic_key_equals, 233 - [SAPP_KEYCODE_A] = tic_key_a, 234 - [SAPP_KEYCODE_B] = tic_key_b, 235 - [SAPP_KEYCODE_C] = tic_key_c, 236 - [SAPP_KEYCODE_D] = tic_key_d, 237 - [SAPP_KEYCODE_E] = tic_key_e, 238 - [SAPP_KEYCODE_F] = tic_key_f, 239 - [SAPP_KEYCODE_G] = tic_key_g, 240 - [SAPP_KEYCODE_H] = tic_key_h, 241 - [SAPP_KEYCODE_I] = tic_key_i, 242 - [SAPP_KEYCODE_J] = tic_key_j, 243 - [SAPP_KEYCODE_K] = tic_key_k, 244 - [SAPP_KEYCODE_L] = tic_key_l, 245 - [SAPP_KEYCODE_M] = tic_key_m, 246 - [SAPP_KEYCODE_N] = tic_key_n, 247 - [SAPP_KEYCODE_O] = tic_key_o, 248 - [SAPP_KEYCODE_P] = tic_key_p, 249 - [SAPP_KEYCODE_Q] = tic_key_q, 250 - [SAPP_KEYCODE_R] = tic_key_r, 251 - [SAPP_KEYCODE_S] = tic_key_s, 252 - [SAPP_KEYCODE_T] = tic_key_t, 253 - [SAPP_KEYCODE_U] = tic_key_u, 254 - [SAPP_KEYCODE_V] = tic_key_v, 255 - [SAPP_KEYCODE_W] = tic_key_w, 256 - [SAPP_KEYCODE_X] = tic_key_x, 257 - [SAPP_KEYCODE_Y] = tic_key_y, 258 - [SAPP_KEYCODE_Z] = tic_key_z, 259 - [SAPP_KEYCODE_LEFT_BRACKET] = tic_key_leftbracket, 260 - [SAPP_KEYCODE_BACKSLASH] = tic_key_backslash, 261 - [SAPP_KEYCODE_RIGHT_BRACKET] = tic_key_rightbracket, 262 - [SAPP_KEYCODE_GRAVE_ACCENT] = tic_key_grave, 263 - [SAPP_KEYCODE_WORLD_1] = tic_key_unknown, 264 - [SAPP_KEYCODE_WORLD_2] = tic_key_unknown, 265 - [SAPP_KEYCODE_ESCAPE] = tic_key_escape, 266 - [SAPP_KEYCODE_ENTER] = tic_key_return, 267 - [SAPP_KEYCODE_TAB] = tic_key_tab, 268 - [SAPP_KEYCODE_BACKSPACE] = tic_key_backspace, 269 - [SAPP_KEYCODE_INSERT] = tic_key_insert, 270 - [SAPP_KEYCODE_DELETE] = tic_key_delete, 271 - [SAPP_KEYCODE_RIGHT] = tic_key_right, 272 - [SAPP_KEYCODE_LEFT] = tic_key_left, 273 - [SAPP_KEYCODE_DOWN] = tic_key_down, 274 - [SAPP_KEYCODE_UP] = tic_key_up, 275 - [SAPP_KEYCODE_PAGE_UP] = tic_key_pageup, 276 - [SAPP_KEYCODE_PAGE_DOWN] = tic_key_pagedown, 277 - [SAPP_KEYCODE_HOME] = tic_key_home, 278 - [SAPP_KEYCODE_END] = tic_key_end, 279 - [SAPP_KEYCODE_CAPS_LOCK] = tic_key_capslock, 280 - [SAPP_KEYCODE_SCROLL_LOCK] = tic_key_unknown, 281 - [SAPP_KEYCODE_NUM_LOCK] = tic_key_unknown, 282 - [SAPP_KEYCODE_PRINT_SCREEN] = tic_key_unknown, 283 - [SAPP_KEYCODE_PAUSE] = tic_key_unknown, 284 - [SAPP_KEYCODE_F1] = tic_key_f1, 285 - [SAPP_KEYCODE_F2] = tic_key_f2, 286 - [SAPP_KEYCODE_F3] = tic_key_f3, 287 - [SAPP_KEYCODE_F4] = tic_key_f4, 288 - [SAPP_KEYCODE_F5] = tic_key_f5, 289 - [SAPP_KEYCODE_F6] = tic_key_f6, 290 - [SAPP_KEYCODE_F7] = tic_key_f7, 291 - [SAPP_KEYCODE_F8] = tic_key_f8, 292 - [SAPP_KEYCODE_F9] = tic_key_f9, 293 - [SAPP_KEYCODE_F10] = tic_key_f10, 294 - [SAPP_KEYCODE_F11] = tic_key_f11, 295 - [SAPP_KEYCODE_F12] = tic_key_f12, 296 - [SAPP_KEYCODE_F13] = tic_key_unknown, 297 - [SAPP_KEYCODE_F14] = tic_key_unknown, 298 - [SAPP_KEYCODE_F15] = tic_key_unknown, 299 - [SAPP_KEYCODE_F16] = tic_key_unknown, 300 - [SAPP_KEYCODE_F17] = tic_key_unknown, 301 - [SAPP_KEYCODE_F18] = tic_key_unknown, 302 - [SAPP_KEYCODE_F19] = tic_key_unknown, 303 - [SAPP_KEYCODE_F20] = tic_key_unknown, 304 - [SAPP_KEYCODE_F21] = tic_key_unknown, 305 - [SAPP_KEYCODE_F22] = tic_key_unknown, 306 - [SAPP_KEYCODE_F23] = tic_key_unknown, 307 - [SAPP_KEYCODE_F24] = tic_key_unknown, 308 - [SAPP_KEYCODE_F25] = tic_key_unknown, 309 - [SAPP_KEYCODE_KP_0] = tic_key_0, 310 - [SAPP_KEYCODE_KP_1] = tic_key_1, 311 - [SAPP_KEYCODE_KP_2] = tic_key_2, 312 - [SAPP_KEYCODE_KP_3] = tic_key_3, 313 - [SAPP_KEYCODE_KP_4] = tic_key_4, 314 - [SAPP_KEYCODE_KP_5] = tic_key_5, 315 - [SAPP_KEYCODE_KP_6] = tic_key_6, 316 - [SAPP_KEYCODE_KP_7] = tic_key_7, 317 - [SAPP_KEYCODE_KP_8] = tic_key_8, 318 - [SAPP_KEYCODE_KP_9] = tic_key_9, 319 - [SAPP_KEYCODE_KP_DECIMAL] = tic_key_unknown, 320 - [SAPP_KEYCODE_KP_DIVIDE] = tic_key_unknown, 321 - [SAPP_KEYCODE_KP_MULTIPLY] = tic_key_unknown, 322 - [SAPP_KEYCODE_KP_SUBTRACT] = tic_key_unknown, 323 - [SAPP_KEYCODE_KP_ADD] = tic_key_unknown, 324 - [SAPP_KEYCODE_KP_ENTER] = tic_key_return, 325 - [SAPP_KEYCODE_KP_EQUAL] = tic_key_equals, 326 - [SAPP_KEYCODE_LEFT_SHIFT] = tic_key_shift, 327 - [SAPP_KEYCODE_LEFT_CONTROL] = tic_key_ctrl, 328 - [SAPP_KEYCODE_LEFT_ALT] = tic_key_alt, 329 - [SAPP_KEYCODE_LEFT_SUPER] = tic_key_unknown, 330 - [SAPP_KEYCODE_RIGHT_SHIFT] = tic_key_shift, 331 - [SAPP_KEYCODE_RIGHT_CONTROL] = tic_key_ctrl, 332 - [SAPP_KEYCODE_RIGHT_ALT] = tic_key_alt, 333 - [SAPP_KEYCODE_RIGHT_SUPER] = tic_key_unknown, 334 - [SAPP_KEYCODE_MENU] = tic_key_unknown, 335 - 336 - }; 337 - 338 - tic_key key = KeyboardCodes[keycode]; 339 - 340 - if(key > tic_key_unknown) 341 - { 342 - // ALT+TAB fix 343 - if(key == tic_key_tab && platform.keyboard.state[tic_key_alt]) 344 - platform.keyboard.state[tic_key_alt] = false; 345 - 346 - platform.keyboard.state[key] = down; 347 - } 348 - } 349 - 350 - static void processMouse(sapp_mousebutton btn, s32 down) 351 - { 352 - tic_mem* tic = platform.studio->tic; 353 - tic80_input* input = &tic->ram.input; 354 - 355 - 356 - switch(btn) 357 - { 358 - case SAPP_MOUSEBUTTON_LEFT: input->mouse.left = down; break; 359 - case SAPP_MOUSEBUTTON_MIDDLE: input->mouse.middle = down; break; 360 - case SAPP_MOUSEBUTTON_RIGHT: input->mouse.right = down; break; 361 - default: break; 362 - } 363 - } 364 - 365 - static void app_input(const sapp_event* event) 366 - { 367 - tic_mem* tic = platform.studio->tic; 368 - tic80_input* input = &tic->ram.input; 369 - 370 - switch(event->type) 371 - { 372 - case SAPP_EVENTTYPE_KEY_DOWN: 373 - handleKeydown(event->key_code, true); 374 - break; 375 - case SAPP_EVENTTYPE_KEY_UP: 376 - handleKeydown(event->key_code, false); 377 - break; 378 - case SAPP_EVENTTYPE_CHAR: 379 - if(event->char_code < 128) 380 - platform.studio->text = event->char_code; 381 - break; 382 - case SAPP_EVENTTYPE_MOUSE_MOVE: 383 - { 384 - struct {s32 x, y, w, h;}rect; 385 - sokol_calc_viewport(&rect.x, &rect.y, &rect.w, &rect.h); 386 - 387 - s32 mx = -1, my = -1; 388 - if(rect.w) mx = ((s32)event->mouse_x - rect.x) * TIC80_FULLWIDTH / rect.w - TIC80_OFFSET_LEFT; 389 - if(rect.h) my = ((s32)event->mouse_y - rect.y) * TIC80_FULLHEIGHT / rect.h - TIC80_OFFSET_TOP; 390 - 391 - input->mouse.x = mx >= 0 && mx < 0xff ? mx : 0xff; 392 - input->mouse.y = my >= 0 && my < 0xff ? my : 0xff; 393 - } 394 - break; 395 - case SAPP_EVENTTYPE_MOUSE_DOWN: 396 - processMouse(event->mouse_button, 1); break; 397 - break; 398 - case SAPP_EVENTTYPE_MOUSE_UP: 399 - processMouse(event->mouse_button, 0); break; 400 - break; 401 - case SAPP_EVENTTYPE_MOUSE_SCROLL: 402 - input->mouse.scrollx = event->scroll_x; 403 - input->mouse.scrolly = event->scroll_y; 404 - break; 405 - default: 406 - break; 407 - } 408 - } 409 - 410 - static void app_cleanup(void) 411 - { 412 - platform.studio->close(); 413 - closeNet(platform.net); 414 - free(platform.audio.samples); 415 - } 416 - 417 - sapp_desc sokol_main(s32 argc, char* argv[]) 418 - { 419 - memset(&platform, 0, sizeof platform); 420 - 421 - platform.audio.desc.num_channels = TIC_STEREO_CHANNELS; 422 - saudio_setup(&platform.audio.desc); 423 - 424 - platform.net = createNet(); 425 - 426 - platform.studio = studioInit(argc, argv, saudio_sample_rate(), "./", &systemInterface); 427 - 428 - const s32 Width = TIC80_FULLWIDTH * platform.studio->config()->uiScale; 429 - const s32 Height = TIC80_FULLHEIGHT * platform.studio->config()->uiScale; 430 - 431 - return(sapp_desc) 432 - { 433 - .init_cb = app_init, 434 - .frame_cb = app_frame, 435 - .event_cb = app_input, 436 - .cleanup_cb = app_cleanup, 437 - .width = Width, 438 - .height = Height, 439 - .window_title = TIC_TITLE, 440 - .ios_keyboard_resizes_canvas = true, 441 - .high_dpi = true, 442 - }; 443 - } 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 <stdio.h> 24 + #include <stdlib.h> 25 + #include <time.h> 26 + #include <limits.h> 27 + 28 + #include "studio/system.h" 29 + #include "system/sokol/sokol.h" 30 + #include "ext/net.h" 31 + 32 + static struct 33 + { 34 + Studio* studio; 35 + 36 + struct 37 + { 38 + bool state[tic_keys_count]; 39 + } keyboard; 40 + 41 + struct 42 + { 43 + saudio_desc desc; 44 + float* samples; 45 + } audio; 46 + 47 + char* clipboard; 48 + 49 + Net* net; 50 + 51 + } platform; 52 + 53 + static void setClipboardText(const char* text) 54 + { 55 + if(platform.clipboard) 56 + { 57 + free(platform.clipboard); 58 + platform.clipboard = NULL; 59 + } 60 + 61 + platform.clipboard = strdup(text); 62 + } 63 + 64 + static bool hasClipboardText() 65 + { 66 + return platform.clipboard != NULL; 67 + } 68 + 69 + static char* getClipboardText() 70 + { 71 + return platform.clipboard ? strdup(platform.clipboard) : NULL; 72 + } 73 + 74 + static void freeClipboardText(const char* text) 75 + { 76 + free((void*)text); 77 + } 78 + 79 + static u64 getPerformanceCounter() 80 + { 81 + return stm_now(); 82 + } 83 + 84 + static u64 getPerformanceFrequency() 85 + { 86 + return 1000000000; 87 + } 88 + 89 + static void* httpGetSync(const char* url, s32* size) 90 + { 91 + return netGetSync(platform.net, url, size); 92 + } 93 + 94 + static void httpGet(const char* url, HttpGetCallback callback, void* calldata) 95 + { 96 + return netGet(platform.net, url, callback, calldata); 97 + } 98 + 99 + static void goFullscreen() 100 + { 101 + } 102 + 103 + static void showMessageBox(const char* title, const char* message) 104 + { 105 + } 106 + 107 + static void setWindowTitle(const char* title) 108 + { 109 + } 110 + 111 + static void openSystemPath(const char* path) 112 + { 113 + 114 + } 115 + 116 + static void preseed() 117 + { 118 + #if defined(__TIC_MACOSX__) 119 + srandom(time(NULL)); 120 + random(); 121 + #else 122 + srand(time(NULL)); 123 + rand(); 124 + #endif 125 + } 126 + 127 + static void pollEvent() 128 + { 129 + 130 + } 131 + 132 + static void updateConfig() 133 + { 134 + 135 + } 136 + 137 + static System systemInterface = 138 + { 139 + .setClipboardText = setClipboardText, 140 + .hasClipboardText = hasClipboardText, 141 + .getClipboardText = getClipboardText, 142 + .freeClipboardText = freeClipboardText, 143 + 144 + .getPerformanceCounter = getPerformanceCounter, 145 + .getPerformanceFrequency = getPerformanceFrequency, 146 + 147 + .httpGetSync = httpGetSync, 148 + .httpGet = httpGet, 149 + 150 + .fileDialogLoad = file_dialog_load, 151 + .fileDialogSave = file_dialog_save, 152 + 153 + .goFullscreen = goFullscreen, 154 + .showMessageBox = showMessageBox, 155 + .setWindowTitle = setWindowTitle, 156 + 157 + .openSystemPath = openSystemPath, 158 + .preseed = preseed, 159 + .poll = pollEvent, 160 + .updateConfig = updateConfig, 161 + }; 162 + 163 + static void app_init(void) 164 + { 165 + sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1, false, true); 166 + 167 + stm_setup(); 168 + 169 + platform.audio.samples = calloc(sizeof platform.audio.samples[0], saudio_sample_rate() / TIC80_FRAMERATE * TIC_STEREO_CHANNELS); 170 + } 171 + 172 + static void handleKeyboard() 173 + { 174 + tic_mem* tic = platform.studio->tic; 175 + 176 + tic80_input* input = &tic->ram.input; 177 + input->keyboard.data = 0; 178 + 179 + enum{BufSize = COUNT_OF(input->keyboard.keys)}; 180 + 181 + for(s32 i = 0, c = 0; i < COUNT_OF(platform.keyboard.state) && c < BufSize; i++) 182 + if(platform.keyboard.state[i]) 183 + input->keyboard.keys[c++] = i; 184 + } 185 + 186 + static void app_frame(void) 187 + { 188 + if(platform.studio->quit) exit(0); 189 + 190 + netTick(platform.net); 191 + 192 + tic_mem* tic = platform.studio->tic; 193 + tic80_input* input = &tic->ram.input; 194 + 195 + input->gamepads.data = 0; 196 + handleKeyboard(); 197 + platform.studio->tick(input); 198 + 199 + sokol_gfx_draw(platform.studio->tic->screen); 200 + 201 + s32 count = tic->samples.size / sizeof tic->samples.buffer[0]; 202 + for(s32 i = 0; i < count; i++) 203 + platform.audio.samples[i] = (float)tic->samples.buffer[i] / SHRT_MAX; 204 + 205 + saudio_push(platform.audio.samples, count / 2); 206 + 207 + input->mouse.scrollx = input->mouse.scrolly = 0; 208 + } 209 + 210 + static void handleKeydown(sapp_keycode keycode, bool down) 211 + { 212 + static const tic_keycode KeyboardCodes[] = 213 + { 214 + [SAPP_KEYCODE_INVALID] = tic_key_unknown, 215 + [SAPP_KEYCODE_SPACE] = tic_key_space, 216 + [SAPP_KEYCODE_APOSTROPHE] = tic_key_apostrophe, 217 + [SAPP_KEYCODE_COMMA] = tic_key_comma, 218 + [SAPP_KEYCODE_MINUS] = tic_key_minus, 219 + [SAPP_KEYCODE_PERIOD] = tic_key_period, 220 + [SAPP_KEYCODE_SLASH] = tic_key_slash, 221 + [SAPP_KEYCODE_0] = tic_key_0, 222 + [SAPP_KEYCODE_1] = tic_key_1, 223 + [SAPP_KEYCODE_2] = tic_key_2, 224 + [SAPP_KEYCODE_3] = tic_key_3, 225 + [SAPP_KEYCODE_4] = tic_key_4, 226 + [SAPP_KEYCODE_5] = tic_key_5, 227 + [SAPP_KEYCODE_6] = tic_key_6, 228 + [SAPP_KEYCODE_7] = tic_key_7, 229 + [SAPP_KEYCODE_8] = tic_key_8, 230 + [SAPP_KEYCODE_9] = tic_key_9, 231 + [SAPP_KEYCODE_SEMICOLON] = tic_key_semicolon, 232 + [SAPP_KEYCODE_EQUAL] = tic_key_equals, 233 + [SAPP_KEYCODE_A] = tic_key_a, 234 + [SAPP_KEYCODE_B] = tic_key_b, 235 + [SAPP_KEYCODE_C] = tic_key_c, 236 + [SAPP_KEYCODE_D] = tic_key_d, 237 + [SAPP_KEYCODE_E] = tic_key_e, 238 + [SAPP_KEYCODE_F] = tic_key_f, 239 + [SAPP_KEYCODE_G] = tic_key_g, 240 + [SAPP_KEYCODE_H] = tic_key_h, 241 + [SAPP_KEYCODE_I] = tic_key_i, 242 + [SAPP_KEYCODE_J] = tic_key_j, 243 + [SAPP_KEYCODE_K] = tic_key_k, 244 + [SAPP_KEYCODE_L] = tic_key_l, 245 + [SAPP_KEYCODE_M] = tic_key_m, 246 + [SAPP_KEYCODE_N] = tic_key_n, 247 + [SAPP_KEYCODE_O] = tic_key_o, 248 + [SAPP_KEYCODE_P] = tic_key_p, 249 + [SAPP_KEYCODE_Q] = tic_key_q, 250 + [SAPP_KEYCODE_R] = tic_key_r, 251 + [SAPP_KEYCODE_S] = tic_key_s, 252 + [SAPP_KEYCODE_T] = tic_key_t, 253 + [SAPP_KEYCODE_U] = tic_key_u, 254 + [SAPP_KEYCODE_V] = tic_key_v, 255 + [SAPP_KEYCODE_W] = tic_key_w, 256 + [SAPP_KEYCODE_X] = tic_key_x, 257 + [SAPP_KEYCODE_Y] = tic_key_y, 258 + [SAPP_KEYCODE_Z] = tic_key_z, 259 + [SAPP_KEYCODE_LEFT_BRACKET] = tic_key_leftbracket, 260 + [SAPP_KEYCODE_BACKSLASH] = tic_key_backslash, 261 + [SAPP_KEYCODE_RIGHT_BRACKET] = tic_key_rightbracket, 262 + [SAPP_KEYCODE_GRAVE_ACCENT] = tic_key_grave, 263 + [SAPP_KEYCODE_WORLD_1] = tic_key_unknown, 264 + [SAPP_KEYCODE_WORLD_2] = tic_key_unknown, 265 + [SAPP_KEYCODE_ESCAPE] = tic_key_escape, 266 + [SAPP_KEYCODE_ENTER] = tic_key_return, 267 + [SAPP_KEYCODE_TAB] = tic_key_tab, 268 + [SAPP_KEYCODE_BACKSPACE] = tic_key_backspace, 269 + [SAPP_KEYCODE_INSERT] = tic_key_insert, 270 + [SAPP_KEYCODE_DELETE] = tic_key_delete, 271 + [SAPP_KEYCODE_RIGHT] = tic_key_right, 272 + [SAPP_KEYCODE_LEFT] = tic_key_left, 273 + [SAPP_KEYCODE_DOWN] = tic_key_down, 274 + [SAPP_KEYCODE_UP] = tic_key_up, 275 + [SAPP_KEYCODE_PAGE_UP] = tic_key_pageup, 276 + [SAPP_KEYCODE_PAGE_DOWN] = tic_key_pagedown, 277 + [SAPP_KEYCODE_HOME] = tic_key_home, 278 + [SAPP_KEYCODE_END] = tic_key_end, 279 + [SAPP_KEYCODE_CAPS_LOCK] = tic_key_capslock, 280 + [SAPP_KEYCODE_SCROLL_LOCK] = tic_key_unknown, 281 + [SAPP_KEYCODE_NUM_LOCK] = tic_key_unknown, 282 + [SAPP_KEYCODE_PRINT_SCREEN] = tic_key_unknown, 283 + [SAPP_KEYCODE_PAUSE] = tic_key_unknown, 284 + [SAPP_KEYCODE_F1] = tic_key_f1, 285 + [SAPP_KEYCODE_F2] = tic_key_f2, 286 + [SAPP_KEYCODE_F3] = tic_key_f3, 287 + [SAPP_KEYCODE_F4] = tic_key_f4, 288 + [SAPP_KEYCODE_F5] = tic_key_f5, 289 + [SAPP_KEYCODE_F6] = tic_key_f6, 290 + [SAPP_KEYCODE_F7] = tic_key_f7, 291 + [SAPP_KEYCODE_F8] = tic_key_f8, 292 + [SAPP_KEYCODE_F9] = tic_key_f9, 293 + [SAPP_KEYCODE_F10] = tic_key_f10, 294 + [SAPP_KEYCODE_F11] = tic_key_f11, 295 + [SAPP_KEYCODE_F12] = tic_key_f12, 296 + [SAPP_KEYCODE_F13] = tic_key_unknown, 297 + [SAPP_KEYCODE_F14] = tic_key_unknown, 298 + [SAPP_KEYCODE_F15] = tic_key_unknown, 299 + [SAPP_KEYCODE_F16] = tic_key_unknown, 300 + [SAPP_KEYCODE_F17] = tic_key_unknown, 301 + [SAPP_KEYCODE_F18] = tic_key_unknown, 302 + [SAPP_KEYCODE_F19] = tic_key_unknown, 303 + [SAPP_KEYCODE_F20] = tic_key_unknown, 304 + [SAPP_KEYCODE_F21] = tic_key_unknown, 305 + [SAPP_KEYCODE_F22] = tic_key_unknown, 306 + [SAPP_KEYCODE_F23] = tic_key_unknown, 307 + [SAPP_KEYCODE_F24] = tic_key_unknown, 308 + [SAPP_KEYCODE_F25] = tic_key_unknown, 309 + [SAPP_KEYCODE_KP_0] = tic_key_0, 310 + [SAPP_KEYCODE_KP_1] = tic_key_1, 311 + [SAPP_KEYCODE_KP_2] = tic_key_2, 312 + [SAPP_KEYCODE_KP_3] = tic_key_3, 313 + [SAPP_KEYCODE_KP_4] = tic_key_4, 314 + [SAPP_KEYCODE_KP_5] = tic_key_5, 315 + [SAPP_KEYCODE_KP_6] = tic_key_6, 316 + [SAPP_KEYCODE_KP_7] = tic_key_7, 317 + [SAPP_KEYCODE_KP_8] = tic_key_8, 318 + [SAPP_KEYCODE_KP_9] = tic_key_9, 319 + [SAPP_KEYCODE_KP_DECIMAL] = tic_key_unknown, 320 + [SAPP_KEYCODE_KP_DIVIDE] = tic_key_unknown, 321 + [SAPP_KEYCODE_KP_MULTIPLY] = tic_key_unknown, 322 + [SAPP_KEYCODE_KP_SUBTRACT] = tic_key_unknown, 323 + [SAPP_KEYCODE_KP_ADD] = tic_key_unknown, 324 + [SAPP_KEYCODE_KP_ENTER] = tic_key_return, 325 + [SAPP_KEYCODE_KP_EQUAL] = tic_key_equals, 326 + [SAPP_KEYCODE_LEFT_SHIFT] = tic_key_shift, 327 + [SAPP_KEYCODE_LEFT_CONTROL] = tic_key_ctrl, 328 + [SAPP_KEYCODE_LEFT_ALT] = tic_key_alt, 329 + [SAPP_KEYCODE_LEFT_SUPER] = tic_key_unknown, 330 + [SAPP_KEYCODE_RIGHT_SHIFT] = tic_key_shift, 331 + [SAPP_KEYCODE_RIGHT_CONTROL] = tic_key_ctrl, 332 + [SAPP_KEYCODE_RIGHT_ALT] = tic_key_alt, 333 + [SAPP_KEYCODE_RIGHT_SUPER] = tic_key_unknown, 334 + [SAPP_KEYCODE_MENU] = tic_key_unknown, 335 + 336 + }; 337 + 338 + tic_key key = KeyboardCodes[keycode]; 339 + 340 + if(key > tic_key_unknown) 341 + { 342 + // ALT+TAB fix 343 + if(key == tic_key_tab && platform.keyboard.state[tic_key_alt]) 344 + platform.keyboard.state[tic_key_alt] = false; 345 + 346 + platform.keyboard.state[key] = down; 347 + } 348 + } 349 + 350 + static void processMouse(sapp_mousebutton btn, s32 down) 351 + { 352 + tic_mem* tic = platform.studio->tic; 353 + tic80_input* input = &tic->ram.input; 354 + 355 + 356 + switch(btn) 357 + { 358 + case SAPP_MOUSEBUTTON_LEFT: input->mouse.left = down; break; 359 + case SAPP_MOUSEBUTTON_MIDDLE: input->mouse.middle = down; break; 360 + case SAPP_MOUSEBUTTON_RIGHT: input->mouse.right = down; break; 361 + default: break; 362 + } 363 + } 364 + 365 + static void app_input(const sapp_event* event) 366 + { 367 + tic_mem* tic = platform.studio->tic; 368 + tic80_input* input = &tic->ram.input; 369 + 370 + switch(event->type) 371 + { 372 + case SAPP_EVENTTYPE_KEY_DOWN: 373 + handleKeydown(event->key_code, true); 374 + break; 375 + case SAPP_EVENTTYPE_KEY_UP: 376 + handleKeydown(event->key_code, false); 377 + break; 378 + case SAPP_EVENTTYPE_CHAR: 379 + if(event->char_code < 128) 380 + platform.studio->text = event->char_code; 381 + break; 382 + case SAPP_EVENTTYPE_MOUSE_MOVE: 383 + { 384 + struct {s32 x, y, w, h;}rect; 385 + sokol_calc_viewport(&rect.x, &rect.y, &rect.w, &rect.h); 386 + 387 + s32 mx = -1, my = -1; 388 + if(rect.w) mx = ((s32)event->mouse_x - rect.x) * TIC80_FULLWIDTH / rect.w - TIC80_OFFSET_LEFT; 389 + if(rect.h) my = ((s32)event->mouse_y - rect.y) * TIC80_FULLHEIGHT / rect.h - TIC80_OFFSET_TOP; 390 + 391 + input->mouse.x = mx >= 0 && mx < 0xff ? mx : 0xff; 392 + input->mouse.y = my >= 0 && my < 0xff ? my : 0xff; 393 + } 394 + break; 395 + case SAPP_EVENTTYPE_MOUSE_DOWN: 396 + processMouse(event->mouse_button, 1); break; 397 + break; 398 + case SAPP_EVENTTYPE_MOUSE_UP: 399 + processMouse(event->mouse_button, 0); break; 400 + break; 401 + case SAPP_EVENTTYPE_MOUSE_SCROLL: 402 + input->mouse.scrollx = event->scroll_x; 403 + input->mouse.scrolly = event->scroll_y; 404 + break; 405 + default: 406 + break; 407 + } 408 + } 409 + 410 + static void app_cleanup(void) 411 + { 412 + platform.studio->close(); 413 + closeNet(platform.net); 414 + free(platform.audio.samples); 415 + } 416 + 417 + sapp_desc sokol_main(s32 argc, char* argv[]) 418 + { 419 + memset(&platform, 0, sizeof platform); 420 + 421 + platform.audio.desc.num_channels = TIC_STEREO_CHANNELS; 422 + saudio_setup(&platform.audio.desc); 423 + 424 + platform.net = createNet(); 425 + 426 + platform.studio = studioInit(argc, argv, saudio_sample_rate(), "./", &systemInterface); 427 + 428 + const s32 Width = TIC80_FULLWIDTH * platform.studio->config()->uiScale; 429 + const s32 Height = TIC80_FULLHEIGHT * platform.studio->config()->uiScale; 430 + 431 + return(sapp_desc) 432 + { 433 + .init_cb = app_init, 434 + .frame_cb = app_frame, 435 + .event_cb = app_input, 436 + .cleanup_cb = app_cleanup, 437 + .width = Width, 438 + .height = Height, 439 + .window_title = TIC_TITLE, 440 + .ios_keyboard_resizes_canvas = true, 441 + .high_dpi = true, 442 + }; 443 + }
+34 -34
src/system/sokol.h src/system/sokol/sokol.h
··· 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 "sokol_app.h" 26 - #include "sokol_gfx.h" 27 - #include "sokol_time.h" 28 - #include "sokol_audio.h" 29 - 30 - #include <stdint.h> 31 - 32 - void sokol_calc_viewport(int* x, int* y, int* w, int* h); 33 - void sokol_gfx_init(int w, int h, int sx, int sy, bool integer_scale, bool portrait_top_align); 34 - void sokol_gfx_draw(const uint32_t* ptr); 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 "sokol_app.h" 26 + #include "sokol_gfx.h" 27 + #include "sokol_time.h" 28 + #include "sokol_audio.h" 29 + 30 + #include <stdint.h> 31 + 32 + void sokol_calc_viewport(int* x, int* y, int* w, int* h); 33 + void sokol_gfx_init(int w, int h, int sx, int sy, bool integer_scale, bool portrait_top_align); 34 + void sokol_gfx_draw(const uint32_t* ptr);
src/system/sokol_gfx.c src/system/sokol/sokol_gfx.c
src/system/sokol_impl.c src/system/sokol/sokol_impl.c
src/system/sokol_impl.m src/system/sokol/sokol_impl.m
+94
src/tilesheet.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com 4 + // Damien de Lemeny @ddelemeny // hello@ddelemeny.me 5 + 6 + // Permission is hereby granted, free of charge, to any person obtaining a copy 7 + // of this software and associated documentation files (the "Software"), to deal 8 + // in the Software without restriction, including without limitation the rights 9 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + // copies of the Software, and to permit persons to whom the Software is 11 + // furnished to do so, subject to the following conditions: 12 + 13 + // The above copyright notice and this permission notice shall be included in all 14 + // copies or substantial portions of the Software. 15 + 16 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + // SOFTWARE. 23 + 24 + #include "tilesheet.h" 25 + 26 + #include <stdlib.h> 27 + 28 + static const tic_blit_segment segments[] = { 29 + // +page +nb_pages 30 + // | +bank +bank_size 31 + // | | | | +sheet_width 32 + // | | | | | +tile_width 33 + {0, 0, 1, 256, 16, 8, TIC_SPRITESIZE, tic_tool_peek1, tic_tool_poke1}, // system gfx 34 + {0, 0, 1, 256, 16, 8, TIC_SPRITESIZE, tic_tool_peek1, tic_tool_poke1}, // system font 35 + {0, 0, 1, 256, 16, 8, sizeof(tic_tile), tic_tool_peek4, tic_tool_poke4}, // 4bpp p0 bg 36 + {0, 1, 1, 256, 16, 8, sizeof(tic_tile), tic_tool_peek4, tic_tool_poke4}, // 4bpp p0 fg 37 + 38 + {0, 0, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p0 bg 39 + {1, 0, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p1 bg 40 + {0, 1, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p0 fg 41 + {1, 1, 2, 512, 32, 16, sizeof(tic_tile), tic_tool_peek2, tic_tool_poke2}, // 2bpp p1 fg 42 + 43 + {0, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p0 bg 44 + {1, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p1 bg 45 + {2, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p2 bg 46 + {3, 0, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p3 bg 47 + {0, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p0 fg 48 + {1, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p1 fg 49 + {2, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p2 fg 50 + {3, 1, 4, 1024, 64, 32, sizeof(tic_tile), tic_tool_peek1, tic_tool_poke1}, // 1bpp p3 fg 51 + }; 52 + 53 + extern u8 tic_tilesheet_getpix(const tic_tilesheet* sheet, s32 x, s32 y); 54 + extern void tic_tilesheet_setpix(const tic_tilesheet* sheet, s32 x, s32 y, u8 value); 55 + extern u8 tic_tilesheet_gettilepix(const tic_tileptr* tile, s32 x, s32 y); 56 + extern void tic_tilesheet_settilepix(const tic_tileptr* tile, s32 x, s32 y, u8 value); 57 + 58 + tic_tilesheet tic_tilesheet_get(u8 segment, u8* ptr) 59 + { 60 + return (tic_tilesheet) { &segments[segment], ptr }; 61 + } 62 + 63 + tic_tileptr tic_tilesheet_gettile(const tic_tilesheet* sheet, s32 index, bool local) 64 + { 65 + enum { Cols = 16, Size = 8 }; 66 + const tic_blit_segment* segment = sheet->segment; 67 + 68 + s32 bank, page, iy, ix; 69 + if (local) { 70 + index = index & 255; 71 + bank = segment->bank_orig; 72 + page = segment->page_orig; 73 + div_t ixy = div(index, Cols); 74 + iy = ixy.quot; 75 + ix = ixy.rem; 76 + } 77 + else { 78 + // reindex 79 + div_t ia = div(index, segment->bank_size); // bank, bank_index 80 + div_t ib = div(ia.rem, segment->sheet_width); // yi, bank_xi 81 + div_t ic = div(ib.rem, Cols); // page, xi 82 + bank = (ia.quot + segment->bank_orig) % 2; 83 + page = (ic.quot + segment->page_orig) % segment->nb_pages; 84 + iy = ib.quot % Cols; 85 + ix = ic.rem; 86 + } 87 + 88 + div_t xdiv = div(ix, segment->nb_pages); // xbuffer, xoffset 89 + u32 ptr_offset = (bank * Cols + iy) * Cols + page * Cols / segment->nb_pages + xdiv.quot; 90 + u8* ptr = sheet->ptr + segment->ptr_size * ptr_offset; 91 + u32 offset = (xdiv.rem * Size); 92 + 93 + return (tic_tileptr) { segment, offset, ptr }; 94 + }
+1 -1
src/tools.h
··· 22 22 23 23 #pragma once 24 24 25 - #include "core/tic.h" 25 + #include "tic.h" 26 26 #include "ext/gif.h" 27 27 #include <stddef.h> 28 28