this repo has no description
0
fork

Configure Feed

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

#1089: cart load/save extracted to cart.c project.c files

nesbox 07c54287 4bdf83e4

+596 -507
+2
CMakeLists.txt
··· 332 332 ${TIC80CORE_DIR}/wrenapi.c 333 333 ${TIC80CORE_DIR}/squirrelapi.c 334 334 ${TIC80CORE_DIR}/ext/gif.c 335 + ${TIC80CORE_DIR}/cart.c 335 336 ) 336 337 337 338 add_library(tic80core STATIC ${TIC80CORE_SRC}) ··· 646 647 ${TIC80LIB_DIR}/menu.c 647 648 ${TIC80LIB_DIR}/surf.c 648 649 ${TIC80LIB_DIR}/net.c 650 + ${TIC80LIB_DIR}/project.c 649 651 ) 650 652 651 653 set(TIC80_OUTPUT tic80)
+211
src/cart.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 "cart.h" 24 + #include <string.h> 25 + #include <stdlib.h> 26 + 27 + typedef enum 28 + { 29 + CHUNK_DUMMY, // 0 30 + CHUNK_TILES, // 1 31 + CHUNK_SPRITES, // 2 32 + CHUNK_COVER, // 3 33 + CHUNK_MAP, // 4 34 + CHUNK_CODE, // 5 35 + CHUNK_FLAGS, // 6 36 + CHUNK_TEMP2, // 7 37 + CHUNK_TEMP3, // 8 38 + CHUNK_SAMPLES, // 9 39 + CHUNK_WAVEFORM, // 10 40 + CHUNK_TEMP4, // 11 41 + CHUNK_PALETTE, // 12 42 + CHUNK_PATTERNS_DEP, // 13 - deprecated chunk 43 + CHUNK_MUSIC, // 14 44 + CHUNK_PATTERNS, // 15 45 + } ChunkType; 46 + 47 + typedef struct 48 + { 49 + ChunkType type:5; 50 + u32 bank:TIC_BANK_BITS; 51 + u32 size:16; // max chunk size is 64K 52 + u32 temp:8; 53 + } Chunk; 54 + 55 + STATIC_ASSERT(tic_chunk_size, sizeof(Chunk) == 4); 56 + 57 + void tic_cart_load(tic_cartridge* cart, const u8* buffer, s32 size) 58 + { 59 + const u8* end = buffer + size; 60 + memset(cart, 0, sizeof(tic_cartridge)); 61 + 62 + #define LOAD_CHUNK(to) memcpy(&to, buffer, MIN(sizeof(to), chunk.size)) 63 + 64 + bool paletteExists = false; 65 + 66 + tic_code* code = calloc(TIC_BANKS, TIC_CODE_SIZE); 67 + 68 + if(!code) return; 69 + 70 + while(buffer < end) 71 + { 72 + Chunk chunk; 73 + memcpy(&chunk, buffer, sizeof(Chunk)); 74 + buffer += sizeof(Chunk); 75 + 76 + switch(chunk.type) 77 + { 78 + case CHUNK_TILES: LOAD_CHUNK(cart->banks[chunk.bank].tiles); break; 79 + case CHUNK_SPRITES: LOAD_CHUNK(cart->banks[chunk.bank].sprites); break; 80 + case CHUNK_MAP: LOAD_CHUNK(cart->banks[chunk.bank].map); break; 81 + case CHUNK_SAMPLES: LOAD_CHUNK(cart->banks[chunk.bank].sfx.samples); break; 82 + case CHUNK_WAVEFORM: LOAD_CHUNK(cart->banks[chunk.bank].sfx.waveforms); break; 83 + case CHUNK_MUSIC: LOAD_CHUNK(cart->banks[chunk.bank].music.tracks); break; 84 + case CHUNK_PATTERNS: LOAD_CHUNK(cart->banks[chunk.bank].music.patterns); break; 85 + case CHUNK_PALETTE: LOAD_CHUNK(cart->banks[chunk.bank].palette); break; 86 + case CHUNK_FLAGS: LOAD_CHUNK(cart->banks[chunk.bank].flags); break; 87 + case CHUNK_CODE: LOAD_CHUNK(code[chunk.bank].data); break; 88 + case CHUNK_COVER: 89 + LOAD_CHUNK(cart->cover.data); 90 + cart->cover.size = chunk.size; 91 + break; 92 + case CHUNK_PATTERNS_DEP: 93 + { 94 + // workaround to load deprecated music patterns section 95 + // and automatically convert volume value to a command 96 + tic_patterns* ptrns = &cart->banks[chunk.bank].music.patterns; 97 + LOAD_CHUNK(*ptrns); 98 + for(s32 i = 0; i < MUSIC_PATTERNS; i++) 99 + for(s32 r = 0; r < MUSIC_PATTERN_ROWS; r++) 100 + { 101 + tic_track_row* row = &ptrns->data[i].rows[r]; 102 + if(row->note >= NoteStart && row->command == tic_music_cmd_empty) 103 + { 104 + row->command = tic_music_cmd_volume; 105 + row->param2 = row->param1 = MAX_VOLUME - row->param1; 106 + } 107 + } 108 + } 109 + break; 110 + default: break; 111 + } 112 + 113 + buffer += chunk.size; 114 + 115 + if(chunk.bank == 0 && chunk.type == CHUNK_PALETTE) 116 + paletteExists = true; 117 + } 118 + 119 + #undef LOAD_CHUNK 120 + 121 + // workaround to load code from banks 122 + if(!strlen(cart->code.data)) 123 + for(s32 i = TIC_BANKS-1; i >= 0; i--) 124 + { 125 + // add new line to split code banks 126 + { 127 + s32 len = strlen(code[i].data); 128 + if(len && len < TIC_CODE_SIZE && code[i].data[len - 1] != '\n') 129 + strcat(code[i].data, "\n"); 130 + } 131 + 132 + if(strlen(code[i].data) + strlen(cart->code.data) < TIC_CODE_SIZE) 133 + strcat(cart->code.data, code[i].data); 134 + else break; 135 + } 136 + 137 + free(code); 138 + 139 + // workaround to support ancient carts without palette 140 + // load DB16 palette if it not exists 141 + if(!paletteExists) 142 + { 143 + static const u8 DB16[] = {0x14, 0x0c, 0x1c, 0x44, 0x24, 0x34, 0x30, 0x34, 0x6d, 0x4e, 0x4a, 0x4e, 0x85, 0x4c, 0x30, 0x34, 0x65, 0x24, 0xd0, 0x46, 0x48, 0x75, 0x71, 0x61, 0x59, 0x7d, 0xce, 0xd2, 0x7d, 0x2c, 0x85, 0x95, 0xa1, 0x6d, 0xaa, 0x2c, 0xd2, 0xaa, 0x99, 0x6d, 0xc2, 0xca, 0xda, 0xd4, 0x5e, 0xde, 0xee, 0xd6}; 144 + memcpy(cart->bank0.palette.data, DB16, sizeof(tic_palette)); 145 + } 146 + } 147 + 148 + 149 + static s32 calcBufferSize(const void* buffer, s32 size) 150 + { 151 + const u8* ptr = (u8*)buffer + size - 1; 152 + const u8* end = (u8*)buffer; 153 + 154 + while(ptr >= end) 155 + { 156 + if(*ptr) break; 157 + 158 + ptr--; 159 + size--; 160 + } 161 + 162 + return size; 163 + } 164 + 165 + static u8* saveFixedChunk(u8* buffer, ChunkType type, const void* from, s32 size, s32 bank) 166 + { 167 + if(size) 168 + { 169 + Chunk chunk = {.type = type, .bank = bank, .size = size, .temp = 0}; 170 + memcpy(buffer, &chunk, sizeof(Chunk)); 171 + buffer += sizeof(Chunk); 172 + memcpy(buffer, from, size); 173 + buffer += size; 174 + } 175 + 176 + return buffer; 177 + } 178 + 179 + static u8* saveChunk(u8* buffer, ChunkType type, const void* from, s32 size, s32 bank) 180 + { 181 + s32 chunkSize = calcBufferSize(from, size); 182 + 183 + return saveFixedChunk(buffer, type, from, chunkSize, bank); 184 + } 185 + 186 + s32 tic_cart_save(const tic_cartridge* cart, u8* buffer) 187 + { 188 + u8* start = buffer; 189 + 190 + #define SAVE_CHUNK(ID, FROM, BANK) saveChunk(buffer, ID, &FROM, sizeof(FROM), BANK) 191 + 192 + for(s32 i = 0; i < TIC_BANKS; i++) 193 + { 194 + buffer = SAVE_CHUNK(CHUNK_TILES, cart->banks[i].tiles, i); 195 + buffer = SAVE_CHUNK(CHUNK_SPRITES, cart->banks[i].sprites, i); 196 + buffer = SAVE_CHUNK(CHUNK_MAP, cart->banks[i].map, i); 197 + buffer = SAVE_CHUNK(CHUNK_SAMPLES, cart->banks[i].sfx.samples, i); 198 + buffer = SAVE_CHUNK(CHUNK_WAVEFORM, cart->banks[i].sfx.waveforms, i); 199 + buffer = SAVE_CHUNK(CHUNK_PATTERNS, cart->banks[i].music.patterns, i); 200 + buffer = SAVE_CHUNK(CHUNK_MUSIC, cart->banks[i].music.tracks, i); 201 + buffer = SAVE_CHUNK(CHUNK_PALETTE, cart->banks[i].palette, i); 202 + buffer = SAVE_CHUNK(CHUNK_FLAGS, cart->banks[i].flags, i); 203 + } 204 + 205 + buffer = SAVE_CHUNK(CHUNK_CODE, cart->code, 0); 206 + buffer = saveFixedChunk(buffer, CHUNK_COVER, cart->cover.data, cart->cover.size, 0); 207 + 208 + #undef SAVE_CHUNK 209 + 210 + return (s32)(buffer - start); 211 + }
+28
src/cart.h
··· 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 + #pragma once 24 + 25 + #include "tic.h" 26 + 27 + void tic_cart_load(tic_cartridge* rom, const u8* buffer, s32 size); 28 + s32 tic_cart_save(const tic_cartridge* rom, u8* buffer);
+4 -2
src/config.c
··· 22 22 23 23 #include "config.h" 24 24 #include "fs.h" 25 + #include "cart.h" 26 + 25 27 #include <lua.h> 26 28 #include <lauxlib.h> 27 29 #include <lualib.h> ··· 287 289 288 290 static void update(Config* config, const u8* buffer, size_t size) 289 291 { 290 - tic_core_load(&config->cart, buffer, size); 292 + tic_cart_load(&config->cart, buffer, size); 291 293 292 294 readConfig(config); 293 295 studioConfigChanged(); ··· 325 327 326 328 if(buffer) 327 329 { 328 - s32 size = tic_core_save(&config->cart, buffer); 330 + s32 size = tic_cart_save(&config->cart, buffer); 329 331 330 332 fsSaveRootFile(config->fs, CONFIG_TIC_PATH, buffer, size, overwrite); 331 333
+12 -294
src/console.c
··· 25 25 #include "config.h" 26 26 #include "ext/gif.h" 27 27 #include "ext/file_dialog.h" 28 + #include "project.h" 28 29 29 30 #include <ctype.h> 30 31 #include <string.h> ··· 383 384 384 385 static bool loadRom(tic_mem* tic, const void* data, s32 size) 385 386 { 386 - tic_core_load(&tic->cart, data, size); 387 + tic_cart_load(&tic->cart, data, size); 387 388 tic_api_reset(tic); 388 389 389 390 return true; ··· 427 428 if(cart) 428 429 { 429 430 tic_mem* tic = console->tic; 430 - tic_core_load(cart, data, size); 431 + tic_cart_load(cart, data, size); 431 432 432 433 switch(i) 433 434 { ··· 682 683 683 684 } 684 685 685 - static const char* projectComment(const char* name) 686 - { 687 - char* comment; 688 - 689 - if(tic_tool_has_ext(name, PROJECT_JS_EXT) 690 - || tic_tool_has_ext(name, PROJECT_WREN_EXT) 691 - || tic_tool_has_ext(name, PROJECT_SQUIRREL_EXT)) 692 - comment = "//"; 693 - else if(tic_tool_has_ext(name, PROJECT_FENNEL_EXT)) 694 - comment = ";;"; 695 - else 696 - comment = "--"; 697 - 698 - return comment; 699 - } 700 - 701 - static void buf2str(const void* data, s32 size, char* ptr, bool flip) 702 - { 703 - enum {Len = 2}; 704 - 705 - for(s32 i = 0; i < size; i++, ptr+=Len) 706 - { 707 - sprintf(ptr, "%02x", ((u8*)data)[i]); 708 - 709 - if(flip) 710 - { 711 - char tmp = ptr[0]; 712 - ptr[0] = ptr[1]; 713 - ptr[1] = tmp; 714 - } 715 - } 716 - } 717 - 718 - static bool bufferEmpty(const u8* data, s32 size) 719 - { 720 - for(s32 i = 0; i < size; i++) 721 - if(*data++) 722 - return false; 723 - 724 - return true; 725 - } 726 - 727 - static char* saveTextSection(char* ptr, const char* data) 728 - { 729 - if(data[0] == '\0') 730 - return ptr; 731 - 732 - sprintf(ptr, "%s\n", data); 733 - ptr += strlen(ptr); 734 - 735 - return ptr; 736 - } 737 - 738 - static char* saveBinaryBuffer(char* ptr, const char* comment, const void* data, s32 size, s32 row, bool flip) 739 - { 740 - if(bufferEmpty(data, size)) 741 - return ptr; 742 - 743 - sprintf(ptr, "%s %03i:", comment, row); 744 - ptr += strlen(ptr); 745 - 746 - buf2str(data, size, ptr, flip); 747 - ptr += strlen(ptr); 748 - 749 - sprintf(ptr, "\n"); 750 - ptr += strlen(ptr); 751 - 752 - return ptr; 753 - } 754 - 755 - static char* saveBinarySection(char* ptr, const char* comment, const char* tag, s32 count, const void* data, s32 size, bool flip) 756 - { 757 - if(bufferEmpty(data, size * count)) 758 - return ptr; 759 - 760 - sprintf(ptr, "%s <%s>\n", comment, tag); 761 - ptr += strlen(ptr); 762 - 763 - for(s32 i = 0; i < count; i++, data = (u8*)data + size) 764 - ptr = saveBinaryBuffer(ptr, comment, data, size, i, flip); 765 - 766 - sprintf(ptr, "%s </%s>\n\n", comment, tag); 767 - ptr += strlen(ptr); 768 - 769 - return ptr; 770 - } 771 - 772 - static const struct BinarySection{const char* tag; s32 count; s32 offset; s32 size; bool flip;} BinarySections[] = 773 - { 774 - {"TILES", TIC_BANK_SPRITES, offsetof(tic_bank, tiles), sizeof(tic_tile), true}, 775 - {"SPRITES", TIC_BANK_SPRITES, offsetof(tic_bank, sprites), sizeof(tic_tile), true}, 776 - {"MAP", TIC_MAP_HEIGHT, offsetof(tic_bank, map), TIC_MAP_WIDTH, true}, 777 - {"WAVES", WAVES_COUNT, offsetof(tic_bank, sfx.waveforms), sizeof(tic_waveform), true}, 778 - {"SFX", SFX_COUNT, offsetof(tic_bank, sfx.samples), sizeof(tic_sample), true}, 779 - {"PATTERNS", MUSIC_PATTERNS, offsetof(tic_bank, music.patterns), sizeof(tic_track_pattern), true}, 780 - {"TRACKS", MUSIC_TRACKS, offsetof(tic_bank, music.tracks), sizeof(tic_track), true}, 781 - {"FLAGS", TIC_SPRITE_BANKS, offsetof(tic_bank, flags), TIC_BANK_SPRITES, true}, 782 - {"PALETTE", 1, offsetof(tic_bank, palette), sizeof(tic_palette), false}, 783 - }; 784 - 785 - static void makeTag(const char* tag, char* out, s32 bank) 786 - { 787 - if(bank) sprintf(out, "%s%i", tag, bank); 788 - else strcpy(out, tag); 789 - } 790 - 791 - static s32 saveProject(Console* console, void* buffer, const char* comment) 792 - { 793 - tic_mem* tic = console->tic; 794 - const tic_cartridge* cart = &tic->cart; 795 - 796 - char* stream = buffer; 797 - char* ptr = saveTextSection(stream, cart->code.data); 798 - char tag[16]; 799 - 800 - for(s32 i = 0; i < COUNT_OF(BinarySections); i++) 801 - { 802 - const struct BinarySection* section = &BinarySections[i]; 803 - 804 - for(s32 b = 0; b < TIC_BANKS; b++) 805 - { 806 - makeTag(section->tag, tag, b); 807 - 808 - ptr = saveBinarySection(ptr, comment, tag, section->count, 809 - (u8*)&cart->banks[b] + section->offset, section->size, section->flip); 810 - } 811 - } 812 - 813 - saveBinarySection(ptr, comment, "COVER", 1, &cart->cover, cart->cover.size + sizeof(s32), true); 814 - 815 - return strlen(stream); 816 - } 817 - 818 - static bool loadTextSection(const char* project, const char* comment, char* dst, s32 size) 819 - { 820 - bool done = false; 821 - 822 - const char* start = project; 823 - const char* end = project + strlen(project); 824 - 825 - { 826 - char tagstart[16]; 827 - sprintf(tagstart, "\n%s <", comment); 828 - 829 - const char* ptr = strstr(project, tagstart); 830 - 831 - if(ptr && ptr < end) 832 - end = ptr; 833 - } 834 - 835 - if(end > start) 836 - { 837 - memcpy(dst, start, MIN(size, end - start)); 838 - done = true; 839 - } 840 - 841 - return done; 842 - } 843 - 844 - static inline const char* getLineEnd(const char* ptr) 845 - { 846 - while(*ptr && isspace(*ptr) && *ptr++ != '\n'); 847 - 848 - return ptr; 849 - } 850 - 851 - static bool loadBinarySection(const char* project, const char* comment, const char* tag, s32 count, void* dst, s32 size, bool flip) 852 - { 853 - char tagbuf[64]; 854 - sprintf(tagbuf, "%s <%s>", comment, tag); 855 - 856 - const char* start = strstr(project, tagbuf); 857 - bool done = false; 858 - 859 - if(start) 860 - { 861 - start += strlen(tagbuf); 862 - start = getLineEnd(start); 863 - 864 - sprintf(tagbuf, "\n%s </%s>", comment, tag); 865 - const char* end = strstr(start, tagbuf); 866 - 867 - if(end > start) 868 - { 869 - const char* ptr = start; 870 - 871 - if(size > 0) 872 - { 873 - while(ptr < end) 874 - { 875 - static char lineStr[] = "999"; 876 - memcpy(lineStr, ptr + sizeof("-- ") - 1, sizeof lineStr - 1); 877 - 878 - s32 index = atoi(lineStr); 879 - 880 - if(index < count) 881 - { 882 - ptr += sizeof("-- 999:") - 1; 883 - str2buf(ptr, size*2, (u8*)dst + size*index, flip); 884 - ptr += size*2 + 1; 885 - 886 - ptr = getLineEnd(ptr); 887 - } 888 - else break; 889 - } 890 - } 891 - else 892 - { 893 - ptr += sizeof("-- 999:") - 1; 894 - str2buf(ptr, end - ptr, (u8*)dst, flip); 895 - } 896 - 897 - done = true; 898 - } 899 - } 900 - 901 - return done; 902 - } 903 - 904 - static bool loadProject(Console* console, const char* name, const char* data, s32 size, tic_cartridge* dst) 905 - { 906 - char* project = (char*)malloc(size+1); 907 - 908 - bool done = false; 909 - 910 - if(project) 911 - { 912 - memcpy(project, data, size); 913 - project[size] = '\0'; 914 - 915 - // remove all the '\r' chars 916 - { 917 - char *s, *d; 918 - for(s = d = project; (*d = *s); d += (*s++ != '\r')); 919 - } 920 - 921 - tic_cartridge* cart = (tic_cartridge*)malloc(sizeof(tic_cartridge)); 922 - 923 - if(cart) 924 - { 925 - memset(cart, 0, sizeof(tic_cartridge)); 926 - 927 - // TODO: should we use DB16 default palette here? 928 - memcpy(&cart->bank0.palette, &getConfig()->cart->bank0.palette.data, sizeof(tic_palette)); 929 - 930 - const char* comment = projectComment(name); 931 - char tag[16]; 932 - 933 - if(loadTextSection(project, comment, cart->code.data, sizeof(tic_code))) 934 - done = true; 935 - 936 - if(done) 937 - { 938 - for(s32 i = 0; i < COUNT_OF(BinarySections); i++) 939 - { 940 - const struct BinarySection* section = &BinarySections[i]; 941 - 942 - for(s32 b = 0; b < TIC_BANKS; b++) 943 - { 944 - makeTag(section->tag, tag, b); 945 - 946 - if(loadBinarySection(project, comment, tag, section->count, (u8*)&cart->banks[b] + section->offset, section->size, section->flip)) 947 - done = true; 948 - } 949 - } 950 - 951 - if(loadBinarySection(project, comment, "COVER", 1, &cart->cover, -1, true)) 952 - done = true; 953 - } 954 - 955 - if(done) 956 - memcpy(dst, cart, sizeof(tic_cartridge)); 957 - 958 - free(cart); 959 - } 960 - 961 - free(project); 962 - } 963 - 964 - return done; 965 - } 966 - 967 686 static void updateProject(Console* console) 968 687 { 969 688 tic_mem* tic = console->tic; ··· 979 698 980 699 if(cart) 981 700 { 982 - if(loadProject(console, console->romName, data, size, cart)) 701 + if(tic_project_load(console->romName, data, size, cart)) 983 702 { 984 703 memcpy(&tic->cart, cart, sizeof(tic_cartridge)); 985 704 ··· 1039 758 1040 759 void* data = fsLoadFile(console->fs, name, &size); 1041 760 1042 - if(data && loadProject(console, name, data, size, &console->tic->cart)) 761 + if(data && tic_project_load(name, data, size, &console->tic->cart)) 1043 762 onCartLoaded(console, name); 1044 763 else printBack(console, "\ncart loading error"); 1045 764 ··· 1930 1649 1931 1650 if(cart) 1932 1651 { 1933 - s32 cartSize = tic_core_save(&tic->cart, cart); 1652 + s32 cartSize = tic_cart_save(&tic->cart, cart); 1934 1653 1935 1654 unsigned long zipSize = sizeof(tic_cartridge); 1936 1655 u8* zipData = (u8*)malloc(zipSize); ··· 2097 1816 2098 1817 if(cart) 2099 1818 { 2100 - s32 cartSize = tic_core_save(&tic->cart, cart); 1819 + s32 cartSize = tic_cart_save(&tic->cart, cart); 2101 1820 2102 1821 zip_entry_open(zip, "cart.tic"); 2103 1822 zip_entry_write(zip, cart, cartSize); ··· 2285 2004 2286 2005 if(hasProjectExt(name)) 2287 2006 { 2288 - size = saveProject(console, buffer, projectComment(name)); 2007 + size = tic_project_save(name, buffer, &tic->cart); 2289 2008 } 2290 2009 else 2291 2010 { 2292 2011 name = getCartName(name); 2293 - size = tic_core_save(&tic->cart, buffer); 2012 + size = tic_cart_save(&tic->cart, buffer); 2294 2013 } 2295 2014 2296 2015 if(size && fsSaveFile(console->fs, name, buffer, size, true)) ··· 3146 2865 { 3147 2866 if(hasProjectExt(name)) 3148 2867 { 3149 - if(loadProject(console, name, data, size, console->embed.file)) 2868 + if(tic_project_load(name, data, size, console->embed.file)) 3150 2869 { 3151 2870 char cartName[TICNAME_MAX]; 3152 2871 fsFilename(name, cartName); ··· 3159 2878 else if(tic_tool_has_ext(name, CART_EXT)) 3160 2879 { 3161 2880 tic_mem* tic = console->tic; 3162 - tic_core_load(console->embed.file, data, size); 2881 + tic_cart_load(console->embed.file, data, size); 3163 2882 3164 2883 char cartName[TICNAME_MAX]; 3165 2884 fsFilename(name, cartName); ··· 3368 3087 .tic = tic, 3369 3088 .config = config, 3370 3089 .load = load, 3371 - .loadProject = loadProject, 3372 3090 .updateProject = updateProject, 3373 3091 .error = error, 3374 3092 .trace = trace, ··· 3533 3251 3534 3252 if(dataSize) 3535 3253 { 3536 - tic_core_load(console->embed.file, data, dataSize); 3254 + tic_cart_load(console->embed.file, data, dataSize); 3537 3255 console->embed.yes = true; 3538 3256 } 3539 3257
-1
src/console.h
··· 104 104 }; 105 105 106 106 void(*load)(Console*, const char* path, const char* hash); 107 - bool(*loadProject)(Console*, const char* name, const char* data, s32 size, tic_cartridge* dst); 108 107 void(*updateProject)(Console*); 109 108 void(*error)(Console*, const char*); 110 109 void(*trace)(Console*, const char*, u8 color);
+304
src/project.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 "project.h" 24 + #include "studio.h" 25 + 26 + #include <stdlib.h> 27 + #include <stdio.h> 28 + #include <string.h> 29 + #include <ctype.h> 30 + 31 + static const struct BinarySection{const char* tag; s32 count; s32 offset; s32 size; bool flip;} BinarySections[] = 32 + { 33 + {"TILES", TIC_BANK_SPRITES, offsetof(tic_bank, tiles), sizeof(tic_tile), true}, 34 + {"SPRITES", TIC_BANK_SPRITES, offsetof(tic_bank, sprites), sizeof(tic_tile), true}, 35 + {"MAP", TIC_MAP_HEIGHT, offsetof(tic_bank, map), TIC_MAP_WIDTH, true}, 36 + {"WAVES", WAVES_COUNT, offsetof(tic_bank, sfx.waveforms), sizeof(tic_waveform), true}, 37 + {"SFX", SFX_COUNT, offsetof(tic_bank, sfx.samples), sizeof(tic_sample), true}, 38 + {"PATTERNS", MUSIC_PATTERNS, offsetof(tic_bank, music.patterns), sizeof(tic_track_pattern), true}, 39 + {"TRACKS", MUSIC_TRACKS, offsetof(tic_bank, music.tracks), sizeof(tic_track), true}, 40 + {"FLAGS", TIC_SPRITE_BANKS, offsetof(tic_bank, flags), TIC_BANK_SPRITES, true}, 41 + {"PALETTE", 1, offsetof(tic_bank, palette), sizeof(tic_palette), false}, 42 + }; 43 + 44 + static void makeTag(const char* tag, char* out, s32 bank) 45 + { 46 + if(bank) sprintf(out, "%s%i", tag, bank); 47 + else strcpy(out, tag); 48 + } 49 + 50 + static void buf2str(const void* data, s32 size, char* ptr, bool flip) 51 + { 52 + enum {Len = 2}; 53 + 54 + for(s32 i = 0; i < size; i++, ptr+=Len) 55 + { 56 + sprintf(ptr, "%02x", ((u8*)data)[i]); 57 + 58 + if(flip) 59 + { 60 + char tmp = ptr[0]; 61 + ptr[0] = ptr[1]; 62 + ptr[1] = tmp; 63 + } 64 + } 65 + } 66 + 67 + static bool bufferEmpty(const u8* data, s32 size) 68 + { 69 + for(s32 i = 0; i < size; i++) 70 + if(*data++) 71 + return false; 72 + 73 + return true; 74 + } 75 + 76 + static char* saveTextSection(char* ptr, const char* data) 77 + { 78 + if(data[0] == '\0') 79 + return ptr; 80 + 81 + sprintf(ptr, "%s\n", data); 82 + ptr += strlen(ptr); 83 + 84 + return ptr; 85 + } 86 + 87 + static char* saveBinaryBuffer(char* ptr, const char* comment, const void* data, s32 size, s32 row, bool flip) 88 + { 89 + if(bufferEmpty(data, size)) 90 + return ptr; 91 + 92 + sprintf(ptr, "%s %03i:", comment, row); 93 + ptr += strlen(ptr); 94 + 95 + buf2str(data, size, ptr, flip); 96 + ptr += strlen(ptr); 97 + 98 + sprintf(ptr, "\n"); 99 + ptr += strlen(ptr); 100 + 101 + return ptr; 102 + } 103 + 104 + static char* saveBinarySection(char* ptr, const char* comment, const char* tag, s32 count, const void* data, s32 size, bool flip) 105 + { 106 + if(bufferEmpty(data, size * count)) 107 + return ptr; 108 + 109 + sprintf(ptr, "%s <%s>\n", comment, tag); 110 + ptr += strlen(ptr); 111 + 112 + for(s32 i = 0; i < count; i++, data = (u8*)data + size) 113 + ptr = saveBinaryBuffer(ptr, comment, data, size, i, flip); 114 + 115 + sprintf(ptr, "%s </%s>\n\n", comment, tag); 116 + ptr += strlen(ptr); 117 + 118 + return ptr; 119 + } 120 + 121 + static const char* projectComment(const char* name) 122 + { 123 + char* comment; 124 + 125 + if(tic_tool_has_ext(name, PROJECT_JS_EXT) 126 + || tic_tool_has_ext(name, PROJECT_WREN_EXT) 127 + || tic_tool_has_ext(name, PROJECT_SQUIRREL_EXT)) 128 + comment = "//"; 129 + else if(tic_tool_has_ext(name, PROJECT_FENNEL_EXT)) 130 + comment = ";;"; 131 + else 132 + comment = "--"; 133 + 134 + return comment; 135 + } 136 + 137 + s32 tic_project_save(const char* name, void* data, const tic_cartridge* cart) 138 + { 139 + const char* comment = projectComment(name); 140 + char* stream = data; 141 + char* ptr = saveTextSection(stream, cart->code.data); 142 + char tag[16]; 143 + 144 + for(s32 i = 0; i < COUNT_OF(BinarySections); i++) 145 + { 146 + const struct BinarySection* section = &BinarySections[i]; 147 + 148 + for(s32 b = 0; b < TIC_BANKS; b++) 149 + { 150 + makeTag(section->tag, tag, b); 151 + 152 + ptr = saveBinarySection(ptr, comment, tag, section->count, 153 + (u8*)&cart->banks[b] + section->offset, section->size, section->flip); 154 + } 155 + } 156 + 157 + saveBinarySection(ptr, comment, "COVER", 1, &cart->cover, cart->cover.size + sizeof(s32), true); 158 + 159 + return strlen(stream); 160 + } 161 + 162 + static bool loadTextSection(const char* project, const char* comment, char* dst, s32 size) 163 + { 164 + bool done = false; 165 + 166 + const char* start = project; 167 + const char* end = project + strlen(project); 168 + 169 + { 170 + char tagstart[16]; 171 + sprintf(tagstart, "\n%s <", comment); 172 + 173 + const char* ptr = strstr(project, tagstart); 174 + 175 + if(ptr && ptr < end) 176 + end = ptr; 177 + } 178 + 179 + if(end > start) 180 + { 181 + memcpy(dst, start, MIN(size, end - start)); 182 + done = true; 183 + } 184 + 185 + return done; 186 + } 187 + 188 + static inline const char* getLineEnd(const char* ptr) 189 + { 190 + while(*ptr && isspace(*ptr) && *ptr++ != '\n'); 191 + 192 + return ptr; 193 + } 194 + 195 + static bool loadBinarySection(const char* project, const char* comment, const char* tag, s32 count, void* dst, s32 size, bool flip) 196 + { 197 + char tagbuf[64]; 198 + sprintf(tagbuf, "%s <%s>", comment, tag); 199 + 200 + const char* start = strstr(project, tagbuf); 201 + bool done = false; 202 + 203 + if(start) 204 + { 205 + start += strlen(tagbuf); 206 + start = getLineEnd(start); 207 + 208 + sprintf(tagbuf, "\n%s </%s>", comment, tag); 209 + const char* end = strstr(start, tagbuf); 210 + 211 + if(end > start) 212 + { 213 + const char* ptr = start; 214 + 215 + if(size > 0) 216 + { 217 + while(ptr < end) 218 + { 219 + static char lineStr[] = "999"; 220 + memcpy(lineStr, ptr + sizeof("-- ") - 1, sizeof lineStr - 1); 221 + 222 + s32 index = atoi(lineStr); 223 + 224 + if(index < count) 225 + { 226 + ptr += sizeof("-- 999:") - 1; 227 + str2buf(ptr, size*2, (u8*)dst + size*index, flip); 228 + ptr += size*2 + 1; 229 + 230 + ptr = getLineEnd(ptr); 231 + } 232 + else break; 233 + } 234 + } 235 + else 236 + { 237 + ptr += sizeof("-- 999:") - 1; 238 + str2buf(ptr, end - ptr, (u8*)dst, flip); 239 + } 240 + 241 + done = true; 242 + } 243 + } 244 + 245 + return done; 246 + } 247 + 248 + bool tic_project_load(const char* name, const char* data, s32 size, tic_cartridge* dst) 249 + { 250 + char* project = (char*)malloc(size+1); 251 + 252 + bool done = false; 253 + 254 + if(project) 255 + { 256 + memcpy(project, data, size); 257 + project[size] = '\0'; 258 + 259 + // remove all the '\r' chars 260 + { 261 + char *s, *d; 262 + for(s = d = project; (*d = *s); d += (*s++ != '\r')); 263 + } 264 + 265 + tic_cartridge* cart = calloc(1, sizeof(tic_cartridge)); 266 + 267 + if(cart) 268 + { 269 + const char* comment = projectComment(name); 270 + char tag[16]; 271 + 272 + if(loadTextSection(project, comment, cart->code.data, sizeof(tic_code))) 273 + done = true; 274 + 275 + if(done) 276 + { 277 + for(s32 i = 0; i < COUNT_OF(BinarySections); i++) 278 + { 279 + const struct BinarySection* section = &BinarySections[i]; 280 + 281 + for(s32 b = 0; b < TIC_BANKS; b++) 282 + { 283 + makeTag(section->tag, tag, b); 284 + 285 + if(loadBinarySection(project, comment, tag, section->count, (u8*)&cart->banks[b] + section->offset, section->size, section->flip)) 286 + done = true; 287 + } 288 + } 289 + 290 + if(loadBinarySection(project, comment, "COVER", 1, &cart->cover, -1, true)) 291 + done = true; 292 + } 293 + 294 + if(done) 295 + memcpy(dst, cart, sizeof(tic_cartridge)); 296 + 297 + free(cart); 298 + } 299 + 300 + free(project); 301 + } 302 + 303 + return done; 304 + }
+28
src/project.h
··· 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 + #pragma once 24 + 25 + #include "cart.h" 26 + 27 + bool tic_project_load(const char* name, const char* data, s32 size, tic_cartridge* dst); 28 + s32 tic_project_save(const char* name, void* data, const tic_cartridge* cart);
+4 -22
src/surf.c
··· 23 23 #include "surf.h" 24 24 #include "fs.h" 25 25 #include "console.h" 26 + #include "project.h" 26 27 27 28 #include "ext/gif.h" 28 29 ··· 511 512 { 512 513 513 514 if(hasProjectExt(item->name)) 514 - surf->console->loadProject(surf->console, item->name, data, size, cart); 515 + tic_project_load(item->name, data, size, cart); 515 516 else 516 - tic_core_load(cart, data, size); 517 + tic_cart_load(cart, data, size); 517 518 518 519 if(cart->cover.size) 519 520 updateMenuItemCover(surf, cart->cover.data, cart->cover.size); ··· 625 626 { 626 627 MenuItem* item = &surf->menu.items[surf->menu.pos]; 627 628 628 - if(item->project) 629 - { 630 - tic_cartridge* cart = malloc(sizeof(tic_cartridge)); 631 - 632 - if(cart) 633 - { 634 - s32 size = 0; 635 - void* data = fsLoadFile(surf->fs, item->name, &size); 636 - 637 - surf->console->loadProject(surf->console, item->name, data, size, cart); 638 - 639 - memcpy(&surf->tic->cart, cart, sizeof(tic_cartridge)); 640 - 641 - studioRomLoaded(); 642 - 643 - free(cart); 644 - } 645 - } 646 - else 647 - surf->console->load(surf->console, item->name, item->hash); 629 + surf->console->load(surf->console, item->name, item->hash); 648 630 649 631 runGameFromSurf(); 650 632 }
+1 -185
src/tic.c
··· 37 37 #include "tilesheet.h" 38 38 #include "machine.h" 39 39 #include "ext/gif.h" 40 + #include "cart.h" 40 41 41 42 #define CLOCKRATE (255<<13) 42 43 #define ENVELOPE_FREQ_SCALE 2 ··· 45 46 #define PIANO_START 8 46 47 #define TRANSPARENT_COLOR 255 47 48 48 - typedef enum 49 - { 50 - CHUNK_DUMMY, // 0 51 - CHUNK_TILES, // 1 52 - CHUNK_SPRITES, // 2 53 - CHUNK_COVER, // 3 54 - CHUNK_MAP, // 4 55 - CHUNK_CODE, // 5 56 - CHUNK_FLAGS, // 6 57 - CHUNK_TEMP2, // 7 58 - CHUNK_TEMP3, // 8 59 - CHUNK_SAMPLES, // 9 60 - CHUNK_WAVEFORM, // 10 61 - CHUNK_TEMP4, // 11 62 - CHUNK_PALETTE, // 12 63 - CHUNK_PATTERNS_DEP, // 13 - deprecated chunk 64 - CHUNK_MUSIC, // 14 65 - CHUNK_PATTERNS, // 15 66 - } ChunkType; 67 - 68 - typedef struct 69 - { 70 - ChunkType type:5; 71 - u32 bank:TIC_BANK_BITS; 72 - u32 size:16; // max chunk size is 64K 73 - u32 temp:8; 74 - } Chunk; 75 - 76 49 STATIC_ASSERT(tic_bank_bits, TIC_BANK_BITS == 3); 77 - STATIC_ASSERT(tic_chunk_size, sizeof(Chunk) == 4); 78 50 STATIC_ASSERT(tic_map, sizeof(tic_map) < 1024*32); 79 51 STATIC_ASSERT(tic_sample, sizeof(tic_sample) == 66); 80 52 STATIC_ASSERT(tic_track_pattern, sizeof(tic_track_pattern) == 3*MUSIC_PATTERN_ROWS); ··· 1907 1879 } 1908 1880 1909 1881 return false; 1910 - } 1911 - 1912 - void tic_core_load(tic_cartridge* cart, const u8* buffer, s32 size) 1913 - { 1914 - const u8* end = buffer + size; 1915 - memset(cart, 0, sizeof(tic_cartridge)); 1916 - 1917 - #define LOAD_CHUNK(to) memcpy(&to, buffer, MIN(sizeof(to), chunk.size)) 1918 - 1919 - bool paletteExists = false; 1920 - 1921 - tic_code* code = calloc(TIC_BANKS, TIC_CODE_SIZE); 1922 - 1923 - if(!code) return; 1924 - 1925 - while(buffer < end) 1926 - { 1927 - Chunk chunk; 1928 - memcpy(&chunk, buffer, sizeof(Chunk)); 1929 - buffer += sizeof(Chunk); 1930 - 1931 - switch(chunk.type) 1932 - { 1933 - case CHUNK_TILES: LOAD_CHUNK(cart->banks[chunk.bank].tiles); break; 1934 - case CHUNK_SPRITES: LOAD_CHUNK(cart->banks[chunk.bank].sprites); break; 1935 - case CHUNK_MAP: LOAD_CHUNK(cart->banks[chunk.bank].map); break; 1936 - case CHUNK_SAMPLES: LOAD_CHUNK(cart->banks[chunk.bank].sfx.samples); break; 1937 - case CHUNK_WAVEFORM: LOAD_CHUNK(cart->banks[chunk.bank].sfx.waveforms); break; 1938 - case CHUNK_MUSIC: LOAD_CHUNK(cart->banks[chunk.bank].music.tracks); break; 1939 - case CHUNK_PATTERNS: LOAD_CHUNK(cart->banks[chunk.bank].music.patterns); break; 1940 - case CHUNK_PALETTE: LOAD_CHUNK(cart->banks[chunk.bank].palette); break; 1941 - case CHUNK_FLAGS: LOAD_CHUNK(cart->banks[chunk.bank].flags); break; 1942 - case CHUNK_CODE: LOAD_CHUNK(code[chunk.bank].data); break; 1943 - case CHUNK_COVER: 1944 - LOAD_CHUNK(cart->cover.data); 1945 - cart->cover.size = chunk.size; 1946 - break; 1947 - case CHUNK_PATTERNS_DEP: 1948 - { 1949 - // workaround to load deprecated music patterns section 1950 - // and automatically convert volume value to a command 1951 - tic_patterns* ptrns = &cart->banks[chunk.bank].music.patterns; 1952 - LOAD_CHUNK(*ptrns); 1953 - for(s32 i = 0; i < MUSIC_PATTERNS; i++) 1954 - for(s32 r = 0; r < MUSIC_PATTERN_ROWS; r++) 1955 - { 1956 - tic_track_row* row = &ptrns->data[i].rows[r]; 1957 - if(row->note >= NoteStart && row->command == tic_music_cmd_empty) 1958 - { 1959 - row->command = tic_music_cmd_volume; 1960 - row->param2 = row->param1 = MAX_VOLUME - row->param1; 1961 - } 1962 - } 1963 - } 1964 - break; 1965 - default: break; 1966 - } 1967 - 1968 - buffer += chunk.size; 1969 - 1970 - if(chunk.bank == 0 && chunk.type == CHUNK_PALETTE) 1971 - paletteExists = true; 1972 - } 1973 - 1974 - #undef LOAD_CHUNK 1975 - 1976 - // workaround to load code from banks 1977 - if(!strlen(cart->code.data)) 1978 - for(s32 i = TIC_BANKS-1; i >= 0; i--) 1979 - { 1980 - // add new line to split code banks 1981 - { 1982 - s32 len = strlen(code[i].data); 1983 - if(len && len < TIC_CODE_SIZE && code[i].data[len - 1] != '\n') 1984 - strcat(code[i].data, "\n"); 1985 - } 1986 - 1987 - if(strlen(code[i].data) + strlen(cart->code.data) < TIC_CODE_SIZE) 1988 - strcat(cart->code.data, code[i].data); 1989 - else break; 1990 - } 1991 - 1992 - free(code); 1993 - 1994 - // workaround to support ancient carts without palette 1995 - // load DB16 palette if it not exists 1996 - if(!paletteExists) 1997 - { 1998 - static const u8 DB16[] = {0x14, 0x0c, 0x1c, 0x44, 0x24, 0x34, 0x30, 0x34, 0x6d, 0x4e, 0x4a, 0x4e, 0x85, 0x4c, 0x30, 0x34, 0x65, 0x24, 0xd0, 0x46, 0x48, 0x75, 0x71, 0x61, 0x59, 0x7d, 0xce, 0xd2, 0x7d, 0x2c, 0x85, 0x95, 0xa1, 0x6d, 0xaa, 0x2c, 0xd2, 0xaa, 0x99, 0x6d, 0xc2, 0xca, 0xda, 0xd4, 0x5e, 0xde, 0xee, 0xd6}; 1999 - memcpy(cart->bank0.palette.data, DB16, sizeof(tic_palette)); 2000 - } 2001 - } 2002 - 2003 - 2004 - static s32 calcBufferSize(const void* buffer, s32 size) 2005 - { 2006 - const u8* ptr = (u8*)buffer + size - 1; 2007 - const u8* end = (u8*)buffer; 2008 - 2009 - while(ptr >= end) 2010 - { 2011 - if(*ptr) break; 2012 - 2013 - ptr--; 2014 - size--; 2015 - } 2016 - 2017 - return size; 2018 - } 2019 - 2020 - static u8* saveFixedChunk(u8* buffer, ChunkType type, const void* from, s32 size, s32 bank) 2021 - { 2022 - if(size) 2023 - { 2024 - Chunk chunk = {.type = type, .bank = bank, .size = size, .temp = 0}; 2025 - memcpy(buffer, &chunk, sizeof(Chunk)); 2026 - buffer += sizeof(Chunk); 2027 - memcpy(buffer, from, size); 2028 - buffer += size; 2029 - } 2030 - 2031 - return buffer; 2032 - } 2033 - 2034 - static u8* saveChunk(u8* buffer, ChunkType type, const void* from, s32 size, s32 bank) 2035 - { 2036 - s32 chunkSize = calcBufferSize(from, size); 2037 - 2038 - return saveFixedChunk(buffer, type, from, chunkSize, bank); 2039 - } 2040 - 2041 - s32 tic_core_save(const tic_cartridge* cart, u8* buffer) 2042 - { 2043 - u8* start = buffer; 2044 - 2045 - #define SAVE_CHUNK(ID, FROM, BANK) saveChunk(buffer, ID, &FROM, sizeof(FROM), BANK) 2046 - 2047 - for(s32 i = 0; i < TIC_BANKS; i++) 2048 - { 2049 - buffer = SAVE_CHUNK(CHUNK_TILES, cart->banks[i].tiles, i); 2050 - buffer = SAVE_CHUNK(CHUNK_SPRITES, cart->banks[i].sprites, i); 2051 - buffer = SAVE_CHUNK(CHUNK_MAP, cart->banks[i].map, i); 2052 - buffer = SAVE_CHUNK(CHUNK_SAMPLES, cart->banks[i].sfx.samples, i); 2053 - buffer = SAVE_CHUNK(CHUNK_WAVEFORM, cart->banks[i].sfx.waveforms, i); 2054 - buffer = SAVE_CHUNK(CHUNK_PATTERNS, cart->banks[i].music.patterns, i); 2055 - buffer = SAVE_CHUNK(CHUNK_MUSIC, cart->banks[i].music.tracks, i); 2056 - buffer = SAVE_CHUNK(CHUNK_PALETTE, cart->banks[i].palette, i); 2057 - buffer = SAVE_CHUNK(CHUNK_FLAGS, cart->banks[i].flags, i); 2058 - } 2059 - 2060 - buffer = SAVE_CHUNK(CHUNK_CODE, cart->code, 0); 2061 - buffer = saveFixedChunk(buffer, CHUNK_COVER, cart->cover.data, cart->cover.size, 0); 2062 - 2063 - #undef SAVE_CHUNK 2064 - 2065 - return (s32)(buffer - start); 2066 1882 } 2067 1883 2068 1884 // copied from SDL2
+2 -1
src/tic80.c
··· 26 26 #include <tic80.h> 27 27 #include "ticapi.h" 28 28 #include "tools.h" 29 + #include "cart.h" 29 30 30 31 #include "ext/gif.h" 31 32 ··· 104 105 } 105 106 106 107 { 107 - tic_core_load(&tic80->memory->cart, cart, size); 108 + tic_cart_load(&tic80->memory->cart, cart, size); 108 109 tic_api_reset(tic80->memory); 109 110 } 110 111 }
-2
src/ticapi.h
··· 174 174 void tic_core_close(tic_mem* memory); 175 175 void tic_core_pause(tic_mem* memory); 176 176 void tic_core_resume(tic_mem* memory); 177 - void tic_core_load(tic_cartridge* rom, const u8* buffer, s32 size); 178 - s32 tic_core_save(const tic_cartridge* rom, u8* buffer); 179 177 void tic_core_tick_start(tic_mem* memory); 180 178 void tic_core_tick(tic_mem* memory, tic_tick_data* data); 181 179 void tic_core_tick_end(tic_mem* memory);