Introduction
POP files, or Pokitto Programs, are like bin files, but can contain a lot more information.
The easiest way to make a POP is with the mkpop tool. Simply drag-and-drop your bin, fill in the title/author/description fields, and optionally drag-and-drop icons and screenshots. If you don’t have icons, it’ll make an attempt at generating one based on the title. It’s good to have at least a screenshot of the title screen.
In total, 4 icons will be stored inside the POP: two small (24x24 4bpp, 24x24 16bpp) and two large (36x36 4bpp, 36x36 16bpp). Color conversion is done automatically using @Pharap’s palette:
Or, if you prefer hex values...
0x181c20,
0x4a5052,
0xa4a19c,
0xffffff,
0x202c9c,
0x5255ff,
0x08a18b,
0x39b2de,
0x8b20ac,
0xf691a4,
0xa42010,
0xff8518,
0xffde39,
0x734429,
0x527d10,
0x83ce18,
If you want to import it in the FemtoIDE image editor...
…here is the palette in Jasc pal format:
pop.pal (206 Bytes)
File Format
POP files are composed of a series of tags, their lengths and their data. There is no header, all tags are optional and can be in any order (though the mkpop tool puts smaller tags first). Unknown tags can be safely ignored and skipped.
With one exception, all tags have the following format:
[4 bytes tag Id] [4 bytes data length ] [ data bytes ]
The CODE tag does not have a data length. All bytes, including the tag id itself until the EOF, are considered the data.
All string tags have a data length and are zero terminated.
An enum with all the tags can be found here.
These are the currently defined tags:
-
0
- PADDING: filler data used to align the following tag (currently unused) -
1
- INDEX: Data contains an index of following tags/offsets (currently unused) -
2
- OFFSETADDRESS: Used together with the CODE tag to define where that code should be located (default is zero) -
3
- CODECHUNK: Contains an offset address (4 bytes) followed by the code to load to that address. -
4
- ENTRYPOINT: Reserved -
5
- CRC: Intended to verify integrity of the game currently loaded in flash. (currently unused). -
6
- HAT: Intended to indicate required/compatible hats -
7
- LONGNAME: String. Name of the game without restrictions. -
8
- AUTHOR: String. Name of the author(s). -
9
- DESCRIPTION: String. Short description of the game. -
10
- IMG_36X36_4BPP: Large,16 color icon bitmap data -
11
- IMG_24X24_4BPP: Small, 16 color icon bitmap data -
12
- IMG_100X24_4BPP: Wide 16 color logo bitmap data (unused) -
13
- IMG_110X88_4BPP: Low-res 16-color screenshot (unused) -
14
- IMG_36X36_565: Large, High-color icon bitmap data -
15
- IMG_24X24_565: Small, High-color icon bitmap data -
16
- IMG_100X24_565: Wide, High-color logo bitmap data (unused) -
17
- IMG_110X88_565: Low-res High-color screenshot (unused) -
18
- IMG_220X176_565: High-res, High-color screenshot -
19
- IMG_200X80_4BPP: 16 color Kraken banner -
20
- IMG_200X80_565: High-color Kraken banner -
21
- VERSION: String that identifies the version of the game -
0x10008000
- CODE: Code that should be loaded into the OFFSETADDRESS. This tag has no size, it’s data is the remainder of the file so it should always be the last.
The mkpop tool currently emits the following tags:
- LONGNAME
- AUTHOR
- DESCRIPTION
- IMG_24X24_4BPP
- IMG_24X24_565
- IMG_36X36_4BPP
- IMG_36X36_565
- IMG_220X176_565 (for each screenshot)
- CODE
Reading POP files
Here’s the basic idea, adapt to your specific use-case.
struct Tag {
uint32_t id;
uint32_t length;
};
Tag tag;
FILE *file = FS.fopen( fileName, "r" );
// While there are still tags to read...
while( FS.fread( &tag, sizeof(tag), 1, file ) != 0 ) {
if( tag.id == tag you want ) {
// Found the tag you're interested in.
// Read the data to a buffer and do something with it.
FS.fread( buffer, tag.length, 1, file );
break;
} else if( tag.id == TAG_CODE ) {
// Need to stop reading tags here.
break;
} else {
// Unknown tag, skip the data to read the next one.
FS.fseek( file, tag.length, SEEK_CUR );
}
}
FS.fclose(file);