-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add metadata packing tool #16
Conversation
The metadata format is pretty crude:
I think the full header would need to be written to Flash in order to ID games stored there? I'm wondering if the cover art should be 64x48 pixels and pixel-doubled for display. That would put the cover art under 10k for a raw image. Enough room to express the character of the game, while being artistically constrained enough to gently encourage a nice pixel art covert instead of a straight up game screenshot or crop. |
In order to make less work for the firmware, I think the metadata should be appended with a small header to point to it. Otherwise:
Maybe something like:
|
I did strongly suspect this would be the case - especially good point about the non-PIC code. Easy enough to change the builder code. How do you feel about it otherwise. Particularly the arbitrary length strings with null terminators? I might settle on giving users a choice of:
This reflects our screen mode choices and offers the same artistic constraints in addition to keeping the metadata payload relatively compact. |
Rough attempt at parsing it seemed okay: struct blit_game_metadata {
std::string title, description, version;
};
void parse_metadata(char *data, uint16_t metadata_len, blit_game_metadata &metadata) {
// parse strings
uint16_t offset = 0;
auto len = strlen(data);
metadata.title = std::string(data, len);
offset += len + 1;
len = strlen(data + offset);
metadata.description = std::string(data + offset, len);
offset += len + 1;
len = strlen(data + offset);
metadata.version = std::string(data + offset, len);
offset += len + 1;
} Will probably need to be more careful about reading it though since the firmware currently only has a 63k heap... |
Haha, nice use of I guess I should add some artificial limits to cap title, description and version to some sensible ranges, too. Maybe 64 chars for title, 1024 for description ( it could scroll, include extra info, etc ) and 16 chars for version which should generally be in the form |
Allows title, description, version, icon and splash to be packed and prepended to a 32blit .bin file. icon should be an 8x8 .png splash should be a 128x96 .png Images can be configured just like the asset pipeline- packed, unpacked, paletted, etc Example metadata.yml: ```yml title: Rocks & Diamonds description: A game of rocks and diamonds version: v1.0.0 icon: file: icon-8x8.png splash: file: splash-128x96.png ```
f768c54
to
90bfa73
Compare
Hmm, it isn't currently possible to have an RGB image. (packed=false is still paletted). Also, with icon and splash both optional it isn't possible to tell which one is there if one was specified but not the other. |
My janky pasted-into-discord patch actually prefixes the icon/splash with "ICON" and "SPLA" for this purpose, but that might... not be good. Re-iterated here for posterity: diff --git a/src/ttblit/tool/metadata.py b/src/ttblit/tool/metadata.py
index 45a7653..0f32c11 100644
--- a/src/ttblit/tool/metadata.py
+++ b/src/ttblit/tool/metadata.py
@@ -3,8 +3,8 @@ import pathlib
import struct
import yaml
+from PIL import Image
-from ..asset.image import ImageAsset
from ..core.tool import Tool
@@ -32,16 +32,24 @@ class Metadata(Tool):
self.config = config
- def prepare_image_asset(self, name, config):
- image_file = pathlib.Path(config.get('file', ''))
- config['input_file'] = image_file
- config['output_file'] = image_file.with_suffix('.bin')
+ def prepare_image_asset(self, name, file):
+ required_size = {'icon': (8, 8), 'splash': (64, 48)}[name]
+ image_file = pathlib.Path(file)
if not image_file.is_file():
raise ValueError(f'{name} "{image_file}" does not exist!')
- asset = ImageAsset(argparse.ArgumentParser().add_subparsers())
- asset.prepare(config)
+ image = Image.open(image_file)
+ image = image.convert('RGB')
- return asset.to_binary(open(image_file, 'rb').read())
+ if not (image.size == required_size):
+ iw, ih = image.size
+ w, h = required_size
+ raise ValueError(f'{name} should be {w}x{h} (is {iw}x{ih})')
+
+ header = bytes(name[:4].upper().encode('utf-8'))
+
+ image = image.tobytes()
+
+ return header + image
def binary_size(self, bin):
return struct.unpack('<I', bin[16:20])[0] & 0xffffff But maybe the best case is to fill with a blank image or something when one or the other is not specified. |
Merging current state, since I want the fixes to tests while I work on #15 |
Allows title, description, version, icon and splash to be packed and prepended to a 32blit .bin file.
icon should be an 8x8 .png
splash should be a 128x96 .png
Images can be configured just like the asset pipeline- packed, unpacked, paletted, etc
Example metadata.yml: