I think you are thinking of the tool that I call C2BIN. The name says it all. So, it pretty much just writes C arrays to a binary file.
I don't do any fancy string parsing (such as with INC2IMG.) You run a shell script that compiles the program each time which outputs the binary files and removes the compiled program since you should have a fresh one each time.
For C2BIN I use data structures and looping to store all the values that I need. I would be happy to share the one that I am using for Bubble Bobble. A key difference between the way that you do music and I do graphics is how they are found. You have a sort of file table at the beginning. I use a list of #defines which are offsets to the proper part of the binary file to read from. Obviously your method has an advantage of portability if other people use the same method. In fact, I expect to adapt to your method a bit. I'll be putting the music in the beginning of the SPIRAM and then my graphics data after that. I'll still do my graphics the way that I am but the music I would use your method for. You read from the beginning of SPIRAM for that file table.
c2bin_runit.sh (compiles c2bin.c and copies the new files to their destination.)
Code: Select all
// Ram tile Maps (only)
#include "C2BIN_RTMAP_tatio2.inc"
#include "C2BIN_RTMAP_info1.inc"
#include "C2BIN_RTMAP_NICKSEN782LOGO1.inc"
#include "C2BIN_RTMAP_gfBubbleF1.inc"
#include "C2BIN_RTMAP_gfBubbleF2.inc"
#include "C2BIN_RTMAP_gfBubbleF3.inc"
#include "C2BIN_RTMAP_gfBubbleF4.inc"
#include "C2BIN_RTMAP_dinos.inc"
#include "C2BIN_RTMAP_endingPlayersF1.inc"
#include "C2BIN_RTMAP_endingPlayersF2.inc"
#include "C2BIN_RTMAP_human.inc"
#include "C2BIN_RTMAP_hugs.inc"
#include "C2BIN_RTMAP_NICKSEN782LOGO2.inc"
#include "C2BIN_RTMAP_NICKSEN782LOGO3.inc"
#include "C2BIN_RTMAP_NICKSEN782LOGO4.inc"
#include "C2BIN_RTMAP_NICKSEN782LOGO5.inc"
void bb_createFile_ramtilemaps (FILE * defs, FILE * dest){
fprintf(defs, "\n\n// C2BIN Offsets Definitions File: bubbleBobble_ramtile_maps\n");
// Write the offset to the defs file.
// Write the number of tiles.
// Write the tileset.
// Write the tilemap.
struct maplist_ {
const char name[30] ;
const char * tileset;
const char * tilemap;
unsigned long tileset_size;
unsigned long tilemap_size;
};
struct maplist_ maplist[] = {
{ .name = "RTMAP_tatio2 " , .tileset = C2BIN_RTMAP_tatio2 , .tilemap = RTMAP_tatio2 , .tileset_size = sizeof(C2BIN_RTMAP_tatio2) , .tilemap_size = sizeof(RTMAP_tatio2) },
{ .name = "RTMAP_info1 " , .tileset = C2BIN_RTMAP_info1 , .tilemap = RTMAP_info1 , .tileset_size = sizeof(C2BIN_RTMAP_info1) , .tilemap_size = sizeof(RTMAP_info1) },
{ .name = "RTMAP_gfBubbleF1 " , .tileset = C2BIN_RTMAP_gfBubbleF1 , .tilemap = RTMAP_gfBubbleF1 , .tileset_size = sizeof(C2BIN_RTMAP_gfBubbleF1) , .tilemap_size = sizeof(RTMAP_gfBubbleF1) },
{ .name = "RTMAP_gfBubbleF2 " , .tileset = C2BIN_RTMAP_gfBubbleF2 , .tilemap = RTMAP_gfBubbleF2 , .tileset_size = sizeof(C2BIN_RTMAP_gfBubbleF2) , .tilemap_size = sizeof(RTMAP_gfBubbleF2) },
{ .name = "RTMAP_gfBubbleF3 " , .tileset = C2BIN_RTMAP_gfBubbleF3 , .tilemap = RTMAP_gfBubbleF3 , .tileset_size = sizeof(C2BIN_RTMAP_gfBubbleF3) , .tilemap_size = sizeof(RTMAP_gfBubbleF3) },
{ .name = "RTMAP_gfBubbleF4 " , .tileset = C2BIN_RTMAP_gfBubbleF4 , .tilemap = RTMAP_gfBubbleF4 , .tileset_size = sizeof(C2BIN_RTMAP_gfBubbleF4) , .tilemap_size = sizeof(RTMAP_gfBubbleF4) },
{ .name = "RTMAP_dinos " , .tileset = C2BIN_RTMAP_dinos , .tilemap = RTMAP_dinos , .tileset_size = sizeof(C2BIN_RTMAP_dinos) , .tilemap_size = sizeof(RTMAP_dinos) },
{ .name = "RTMAP_endingPlayersF1" , .tileset = C2BIN_RTMAP_endingPlayersF1, .tilemap = RTMAP_endingPlayersF1, .tileset_size = sizeof(C2BIN_RTMAP_endingPlayersF1) , .tilemap_size = sizeof(RTMAP_endingPlayersF1) },
{ .name = "RTMAP_endingPlayersF2" , .tileset = C2BIN_RTMAP_endingPlayersF2, .tilemap = RTMAP_endingPlayersF2, .tileset_size = sizeof(C2BIN_RTMAP_endingPlayersF2) , .tilemap_size = sizeof(RTMAP_endingPlayersF2) },
{ .name = "RTMAP_human " , .tileset = C2BIN_RTMAP_human , .tilemap = RTMAP_human , .tileset_size = sizeof(C2BIN_RTMAP_human) , .tilemap_size = sizeof(RTMAP_human) },
{ .name = "RTMAP_hugs " , .tileset = C2BIN_RTMAP_hugs , .tilemap = RTMAP_hugs , .tileset_size = sizeof(C2BIN_RTMAP_hugs) , .tilemap_size = sizeof(RTMAP_hugs) },
{ .name = "RTMAP_NICKSEN782LOGO1" , .tileset = C2BIN_RTMAP_NICKSEN782LOGO1, .tilemap = RTMAP_NICKSEN782LOGO1, .tileset_size = sizeof(C2BIN_RTMAP_NICKSEN782LOGO1) , .tilemap_size = sizeof(RTMAP_NICKSEN782LOGO1) },
{ .name = "RTMAP_NICKSEN782LOGO5" , .tileset = C2BIN_RTMAP_NICKSEN782LOGO5, .tilemap = RTMAP_NICKSEN782LOGO5, .tileset_size = sizeof(C2BIN_RTMAP_NICKSEN782LOGO5) , .tilemap_size = sizeof(RTMAP_NICKSEN782LOGO5) },
{ .name = "RTMAP_NICKSEN782LOGO4" , .tileset = C2BIN_RTMAP_NICKSEN782LOGO4, .tilemap = RTMAP_NICKSEN782LOGO4, .tileset_size = sizeof(C2BIN_RTMAP_NICKSEN782LOGO4) , .tilemap_size = sizeof(RTMAP_NICKSEN782LOGO4) },
{ .name = "RTMAP_NICKSEN782LOGO3" , .tileset = C2BIN_RTMAP_NICKSEN782LOGO3, .tilemap = RTMAP_NICKSEN782LOGO3, .tileset_size = sizeof(C2BIN_RTMAP_NICKSEN782LOGO3) , .tilemap_size = sizeof(RTMAP_NICKSEN782LOGO3) },
{ .name = "RTMAP_NICKSEN782LOGO2" , .tileset = C2BIN_RTMAP_NICKSEN782LOGO2, .tilemap = RTMAP_NICKSEN782LOGO2, .tileset_size = sizeof(C2BIN_RTMAP_NICKSEN782LOGO2) , .tilemap_size = sizeof(RTMAP_NICKSEN782LOGO2) },
};
unsigned int maplist_size = sizeof(maplist) / sizeof(maplist[0]);
unsigned long thisRecordSize=0;
unsigned int banksize = 0xFF00;
for(unsigned char i=0; i<maplist_size; i+=1){
// Defs line.
fprintf(defs, "#define %s %lu \t// %d/%d -- Uniques: %lu -- Map bytes: %lu, -- Dims: %d by %d \n", maplist[i].name, ftell(dest), i+1, maplist_size, maplist[i].tileset_size/64, maplist[i].tilemap_size, maplist[i].tilemap[0], maplist[i].tilemap[1] );
// Number of tiles.
fputc ( maplist[i].tileset_size/64, dest );
// Tileset.
fwrite(maplist[i].tileset, sizeof(const char), maplist[i].tileset_size, dest);
// Tilemap.
fwrite(maplist[i].tilemap, sizeof(const char), maplist[i].tilemap_size, dest);
}
}
int main(){
// Files:
// Open the output files.
F_SPIRAM = fopen (FNAME_SPIRAM , "wb+"); // File 7: spiramSR.bin : FNAME_SPIRAM: Holds the combined SD data as one file.
F_defineSPIRAM = fopen (FNAME_defineSPIRAM , "wb+"); // File 8: defineSR.def : FNAME_defineSPIRAM: Holds defines for SPI RAM usage.
// Padding for the SD and SPI RAM files.
unsigned int padBytes=0;
// Write the SPIRAM file.
fprintf(F_defineSPIRAM, "// C2BIN DEFINITIONS: SPI RAM (%s) \n\n", FNAME_defineSPIRAM);
unsigned long offset_gamesave = ftell(F_SPIRAM);
bb_createFile_gamesave ( F_defineSPIRAM, F_SPIRAM );
unsigned long offset_leveltiles = ftell(F_SPIRAM);
bb_createFile_levelTiles ( F_defineSPIRAM, F_SPIRAM );
unsigned long offset_leveldata = ftell(F_SPIRAM);
bb_createFile_levelData ( F_defineSPIRAM, F_SPIRAM );
unsigned long offset_flashtilemaps = ftell(F_SPIRAM);
bb_createFile_flashtilemaps ( F_defineSPIRAM, F_SPIRAM );
unsigned long offset_ramtilemaps = ftell(F_SPIRAM);
bb_createFile_ramtilemaps ( F_defineSPIRAM, F_SPIRAM );
unsigned long offset_music = ftell(F_SPIRAM);
bb_createFile_music ( F_defineSPIRAM, F_SPIRAM );
// Seek to the end of each of the opened files.
fseek(F_defineSPIRAM, 0L, SEEK_END);
fseek(F_SPIRAM, 0L, SEEK_END);
padBytes = ftell(F_SPIRAM) % 512 ;
// Pad out bytes until the next 512 byte offset.
// for(unsigned int i=0; i<padBytes; i++){ fputc ( 'X', F_SPIRAM ); }
// Write the section offsets to the end of the define file.
fprintf(F_defineSPIRAM, "\n\n");
fprintf(F_defineSPIRAM, "// ***** SECTION OFFSETS *****\n");
fprintf(F_defineSPIRAM, "#define offset_gamesave %lu \n", offset_gamesave );
fprintf(F_defineSPIRAM, "#define offset_leveltiles %lu \n", offset_leveltiles );
fprintf(F_defineSPIRAM, "#define offset_leveldata %lu \n", offset_leveldata );
fprintf(F_defineSPIRAM, "#define offset_flashtilemaps %lu \n", offset_flashtilemaps );
fprintf(F_defineSPIRAM, "#define offset_ramtilemaps %lu \n", offset_ramtilemaps );
fprintf(F_defineSPIRAM, "#define offset_music %lu \n", offset_music );
fprintf(F_defineSPIRAM, "#define offset_endofspiram %lu \n", ftell(F_SPIRAM) );
// midisong1
// Output some summary data to the console.
printf("\n");
printf("// ***** C2BIN END *****\n");
printf("// ** Compile Date: %s \n", __DATE__);
printf("// ** Compile Time: %s \n", __TIME__);
printf("// -----------------------------------------------\n" );
// printf("// Definition file size: SD offsets : (%s) : (%lu bytes)\n", FNAME_defineSD, ftell(F_defineSD) );
printf("// Definition file size: SPIRAM offsets: (%s) : (%lu bytes)\n", FNAME_SPIRAM, ftell(F_defineSPIRAM) );
printf("// -----------------------------------------------\n" );
printf("// File size for SPI RAM:\n" );
printf("// File 1 : (%s) : (%lu bytes)\n", FNAME_SPIRAM, ftell(F_SPIRAM) );
printf("// -----------------------------------------------\n" );
printf("// SPIRAM Section Offsets\n" );
printf("// offset_gamesave : %lu \n", offset_gamesave );
printf("// offset_leveltiles : %lu \n", offset_leveltiles );
printf("// offset_leveldata : %lu \n", offset_leveldata );
printf("// offset_flashtilemaps : %lu \n", offset_flashtilemaps );
printf("// offset_ramtilemaps : %lu \n", offset_ramtilemaps );
printf("// offset_ramtilemaps : %lu \n", offset_ramtilemaps );
printf("// offset_music : %lu \n", offset_music );
printf("// END OF FILE PAD BYTES: %d \n", padBytes );
printf("// -----------------------------------------------\n" );
// Close the output files.
fclose(F_defineSPIRAM);
fclose(F_SPIRAM);
// Final console output string. (Do not change. Used as a token to detect C2BIN completion.)
printf("// C 2 Bin - DONE!\n");
}
Example code for writing a ram tile map to the screen.
That's how I've been creating my binary file. Just put a new entry into the data structure for that type of data and then loop through. Keep track of offsets along the way and use them to make a defines file. And at the end provide a bunch of information since I like to see it even through the offsets are kinda automatic.
When reading something like a tilemap from SPIRAM I do much like how I did with SD. Open the file (not really needed with SPIRAM), go to the beginning offset and read data.