| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- #include "sprite.h"
- struct Sprite {
- uint8_t width;
- uint8_t height;
- uint8_t width_in_bytes;
- uint8_t* data;
- };
- #define TAG "Sprite"
- static void sprite_set_pixel(Sprite* sprite, uint8_t x, uint8_t y, bool color) {
- size_t p = y * sprite->width_in_bytes + x / 8;
- size_t b = x % 8;
- if(color) {
- sprite->data[p] |= 1 << b;
- } else {
- sprite->data[p] &= ~(1 << b);
- }
- }
- static bool sprite_load(Storage* storage, const char* bmp_path, Sprite* sprite) {
- bool result = false;
- File* file = storage_file_alloc(storage);
- do {
- if(!storage_file_open(file, bmp_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
- FURI_LOG_E(TAG, "Failed to open file: %s", bmp_path);
- break;
- }
- // actually header is 54 bytes, but we only need first 38
- uint8_t header[38];
- if(!storage_file_read(file, header, sizeof(header))) {
- FURI_LOG_E(TAG, "Failed to read file header");
- break;
- }
- // check if it's a bmp file
- if(header[0] != 'B' || header[1] != 'M') {
- FURI_LOG_E(TAG, "Invalid BMP header");
- break;
- }
- // load bmp info
- const uint32_t data_offset = *(uint32_t*)&header[10];
- const uint32_t width = *(uint32_t*)&header[18];
- const uint32_t height = *(uint32_t*)&header[22];
- const uint16_t bpp = *(uint16_t*)&header[28];
- const uint32_t size = *(uint32_t*)&header[34];
- uint8_t* data = malloc(size);
- storage_file_seek(file, data_offset, true);
- if(!storage_file_read(file, data, size)) {
- FURI_LOG_E(TAG, "Failed to read file data");
- free(data);
- break;
- }
- sprite->width = width;
- sprite->height = height;
- sprite->width_in_bytes = width / 8 + (width % 8 ? 1 : 0);
- sprite->data = malloc(sprite->width_in_bytes * sprite->height);
- // convert bmp data to 1-bit xbm
- size_t p = 0;
- size_t x = 0;
- size_t y = 0;
- const size_t bpp_in_bytes = bpp / 8;
- while(p < size) {
- // sum all bytes in pixel
- uint32_t bmp_px = 0;
- for(size_t i = 0; i < bpp_in_bytes; i++) {
- bmp_px += data[p + i];
- }
- p += bpp_in_bytes;
- // if sum divided by bytes per pixel is less than 128, it's a black pixel
- bool color = bmp_px / (bpp_in_bytes) < 128;
- // set pixel
- sprite_set_pixel(sprite, x, height - y - 1, color);
- // advance to next pixel
- x++;
- // advance to next row
- if(x >= width) {
- // consider that bmp data is padded to 4 bytes
- size_t row_reminder = p % 4;
- if(row_reminder) {
- p += 4 - row_reminder;
- }
- x = 0;
- y++;
- }
- }
- free(data);
- result = true;
- } while(false);
- storage_file_free(file);
- return result;
- }
- Sprite* sprite_alloc() {
- Sprite* sprite = malloc(sizeof(Sprite));
- sprite->width = 0;
- sprite->height = 0;
- sprite->data = NULL;
- return sprite;
- }
- bool sprite_load_from_bmp(Sprite* sprite, Storage* storage, const char* bmp_path) {
- return sprite_load(storage, bmp_path, sprite);
- }
- void sprite_free(Sprite* sprite) {
- free(sprite->data);
- free(sprite);
- }
- size_t sprite_get_width(Sprite* sprite) {
- return sprite->width;
- }
- size_t sprite_get_height(Sprite* sprite) {
- return sprite->height;
- }
- void canvas_draw_sprite(Canvas* canvas, Sprite* sprite, int32_t x, int32_t y) {
- furi_check(sprite->width);
- furi_check(sprite->height);
- furi_check(sprite->data);
- canvas_draw_xbm(canvas, x, y, sprite->width, sprite->height, sprite->data);
- }
|