SG 1 anno fa
parent
commit
0ee6802adf
2 ha cambiato i file con 192 aggiunte e 0 eliminazioni
  1. 140 0
      sprite.c
  2. 52 0
      sprite.h

+ 140 - 0
sprite.c

@@ -0,0 +1,140 @@
+#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) {
+    canvas_draw_xbm(canvas, x, y, sprite->width, sprite->height, sprite->data);
+}

+ 52 - 0
sprite.h

@@ -0,0 +1,52 @@
+#pragma once
+#include <stdbool.h>
+#include <storage/storage.h>
+#include <gui/canvas.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Sprite Sprite;
+
+/** Sprite allocator
+ * @return Sprite*  Sprite instance
+ */
+Sprite* sprite_alloc();
+
+/** Load sprite from bmp file
+ * @param sprite Sprite instance
+ * @param storage Storage instance
+ * @param bmp_path path to bmp file
+ * @return bool true if success
+ */
+bool sprite_load_from_bmp(Sprite* sprite, Storage* storage, const char* bmp_path);
+
+/** Sprite deallocator
+ * @param sprite Sprite instance
+ */
+void sprite_free(Sprite* sprite);
+
+/** Get sprite width
+ * @param sprite Sprite instance
+ * @return size_t sprite width
+ */
+size_t sprite_get_width(Sprite* sprite);
+
+/** Get sprite height
+ * @param sprite Sprite instance
+ * @return size_t sprite height
+ */
+size_t sprite_get_height(Sprite* sprite);
+
+/** Draw sprite on canvas
+ * @param canvas Canvas instance
+ * @param sprite Sprite instance
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+void canvas_draw_sprite(Canvas* canvas, Sprite* sprite, int32_t x, int32_t y);
+
+#ifdef __cplusplus
+}
+#endif