diff --git a/flake.nix b/flake.nix index df69be9..f00e9b3 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,7 @@ inputs = { # pebble.url = "github:pebble-dev/pebble.nix"; - pebble.url = "github:diomidov/pebble.nix"; + pebble.url = "github:diomidova/pebble.nix"; flake-utils.url = "github:numtide/flake-utils"; }; diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..99704d5 Binary files /dev/null and b/icon.png differ diff --git a/package.json b/package.json index 7504a16..03a19f7 100644 --- a/package.json +++ b/package.json @@ -32,17 +32,20 @@ { "type": "bitmap", "name": "DIGITS", - "file": "digits.png" + "file": "digits.png", + "memoryFormat": "1BitPalette" }, { "type": "bitmap", "name": "FRAME", - "file": "frame.png" + "file": "frame.png", + "memoryFormat": "1BitPalette" }, { "type": "bitmap", "name": "MENU_ICON", "file": "icon.png", + "memoryFormat": "2BitPalette", "menuIcon": true } ] diff --git a/resources/digits.png b/resources/digits.png index 7e2a67f..a293531 100644 Binary files a/resources/digits.png and b/resources/digits.png differ diff --git a/resources/frame.png b/resources/frame.png index c95a22c..1252983 100644 Binary files a/resources/frame.png and b/resources/frame.png differ diff --git a/src/c/bitmaps.cpp b/src/c/bitmaps.cpp new file mode 100644 index 0000000..5e2b4aa --- /dev/null +++ b/src/c/bitmaps.cpp @@ -0,0 +1,98 @@ +#include "bitmaps.hpp" +#include <@rebble/sdk-c-utils/macros.h> + +using namespace Pebble; + +// TODO move this to pebble-cpp +bool operator==(const GColor8& lhs, const GColor8& rhs) { return lhs.argb == rhs.argb; } +bool operator!=(const GColor8& lhs, const GColor8& rhs) { return lhs.argb != rhs.argb; } + +namespace { + GOwnedBitmap digitsBitmap; + GOwnedBitmap digitBitmaps[10]; + GOwnedBitmap frameBitmap; + + GColor* digitColor; + GColor* frameColor; + + + int get_palette_size(GBitmapBase& bitmap){ + switch (bitmap.GetFormat()) { + case GBitmapFormat1BitPalette: return 2; + case GBitmapFormat2BitPalette: return 4; + case GBitmapFormat4BitPalette: return 16; + default: return 0; + } + } + + GColor* find_color(GBitmapBase& bitmap, GColor color) { + GColor* palette = bitmap.GetPalette(); + if (palette == nullptr) { + ERROR("Palette is null"); + return nullptr; + } + + int paletteSize = get_palette_size(bitmap); + if (paletteSize == 0) { + ERROR("Expected GBitmapFormat[124]BitPalette, got: %d", digitsBitmap.GetFormat()); + return nullptr; + } + for (int i = 0; i < paletteSize; i++) { + if (palette[i] == color) { + DEBUG("Found color 0x%02X at index %d", color, i); + return &palette[i]; + } + } + ERROR("Color 0x%02X not found in the palette", color); + return nullptr; + } +} + +void init_bitmaps() { + digitsBitmap = GOwnedBitmap::CreateWithResource(RESOURCE_ID_DIGITS); + auto size = digitsBitmap.GetBounds().size; + uint16_t w = size.w / 10; + uint16_t h = size.h; + for (int i = 0; i < 10; i++) { + digitBitmaps[i] = GOwnedBitmap::CreateSubBitmap(digitsBitmap, Pebble::GRect(i * w, 0, w, h)); + } + + frameBitmap = GOwnedBitmap::CreateWithResource(RESOURCE_ID_FRAME); + + digitColor = find_color(digitsBitmap, GColorBlack); + frameColor = find_color(frameBitmap, GColorBlack); +} + +void deinit_bitmaps() { + for (int i = 0; i < 10; i++) { + digitBitmaps[i] = GOwnedBitmap(); + } + digitsBitmap = GOwnedBitmap(); + frameBitmap = GOwnedBitmap(); + digitColor = nullptr; + frameColor = nullptr; +} + +GBitmapBase& get_digit_bitmap(uint16_t digit) {return digitBitmaps[digit];} +GBitmapBase& get_frame_bitmap() {return frameBitmap;} + + +void set_digit_color(GColor color) { + if (digitColor != nullptr) *digitColor = color; +} +void set_frame_color(GColor color) { + if (frameColor != nullptr) *frameColor = color; +} + +void print_palette(GBitmapBase& bitmap) { + int paletteSize = get_palette_size(bitmap); + if (paletteSize == 0) { + ERROR("Expected GBitmapFormat[124]BitPalette, got: %d", digitsBitmap.GetFormat()); + return; + } + DEBUG("%d colors:", paletteSize); + GColor8* palette = bitmap.GetPalette(); + for (int i = 0; i < paletteSize; i++) { + DEBUG("* 0x%02X = argb(%d,%d,%d,%d)", palette[i].argb, palette[i].a, palette[i].r, palette[i].g, palette[i].b); + } +} \ No newline at end of file diff --git a/src/c/bitmaps.hpp b/src/c/bitmaps.hpp new file mode 100644 index 0000000..a4a7c31 --- /dev/null +++ b/src/c/bitmaps.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +void init_bitmaps(); +void deinit_bitmaps(); +Pebble::GBitmapBase& get_digit_bitmap(uint16_t digit); +Pebble::GBitmapBase& get_frame_bitmap(); +void set_digit_color(GColor color); +void set_frame_color(GColor color); +void print_palette(Pebble::GBitmapBase& bitmap); \ No newline at end of file diff --git a/src/c/cryptic_clock.cpp b/src/c/cryptic_clock.cpp index 1a8c7f9..9e5ce68 100644 --- a/src/c/cryptic_clock.cpp +++ b/src/c/cryptic_clock.cpp @@ -1,7 +1,8 @@ #include -#include "pebble_bitmap_layer.hpp" #include <@rebble/sdk-c-utils/macros.h> +#include "pebble_bitmap_layer.hpp" #include "digit_layer.hpp" +#include "bitmaps.hpp" using namespace Pebble; @@ -9,10 +10,11 @@ using namespace Pebble; class MainWindow : public AppWindow, public TickTimer { DigitLayer digitLayers[4]; - GOwnedBitmap frameBitmap; Pebble::BitmapLayer frameLayer; protected: void OnLoad() { + init_bitmaps(); + auto bounds = this->GetBounds(); int16_t w2 = bounds.size.w / 2; int16_t h = bounds.size.h; @@ -30,8 +32,12 @@ protected: this->AddChild(this->digitLayers[i]); } - this->frameBitmap = Pebble::GOwnedBitmap::CreateWithResource(RESOURCE_ID_FRAME); - this->frameLayer.SetBitmap(this->frameBitmap); + // print_palette(get_digit_bitmap(0)); + // print_palette(get_frame_bitmap()); + // set_frame_color(GColorPictonBlue); + // print_palette(get_digit_bitmap(0)); + // print_palette(get_frame_bitmap()); + this->frameLayer.SetBitmap(get_frame_bitmap()); this->frameLayer.SetFrame(bounds); this->frameLayer.SetCompositingMode(GCompOpSet); this->AddChild(this->frameLayer); @@ -42,6 +48,14 @@ protected: TickTimerStart(MINUTE_UNIT); #endif UpdateTime(false); + + this->SetBackgroundColor(GColorBlack); + set_digit_color(GColorVividCerulean); + set_frame_color(GColorPictonBlue); + } + + void OnUnload() { + deinit_bitmaps(); } void UpdateTime(bool animate=true) { diff --git a/src/c/digit_layer.cpp b/src/c/digit_layer.cpp index c7ba869..bc2af76 100644 --- a/src/c/digit_layer.cpp +++ b/src/c/digit_layer.cpp @@ -1,37 +1,21 @@ #include "digit_layer.hpp" +#include "bitmaps.hpp" #include <@rebble/sdk-c-utils/macros.h> using namespace Pebble; namespace { - // NOTE: technically a memory leak, destructor will never be called. - // Can't make it a static variable in draw_digit, because `atexit` is broken on Pebble. - static GOwnedBitmap digitBitmaps[10]; - static bool bitmapsInitialized = false; - - static void draw_digit(const Pebble::GContext& ctx, const Pebble::GRect& bounds, const uint16_t digit) { - if (!bitmapsInitialized) { - auto bitmap = GOwnedBitmap::CreateWithResource(RESOURCE_ID_DIGITS); - auto size = bitmap.GetBounds().size; - uint16_t w = size.w / 10; - uint16_t h = size.h; - for (int i = 0; i < 10; i++) { - digitBitmaps[i] = GOwnedBitmap::CreateSubBitmap(bitmap, Pebble::GRect(i * w, 0, w, h)); - } - bitmapsInitialized = true; - } - - auto bitmap = &digitBitmaps[digit]; - auto rect = bitmap->GetBounds(); + void draw_digit(const Pebble::GContext& ctx, const Pebble::GRect& bounds, const uint16_t digit) { + Pebble::GBitmapBase& bitmap = get_digit_bitmap(digit); + auto rect = bitmap.GetBounds(); rect.Align(bounds, GAlignCenter, false); - ctx.DrawBitmapInRect(*bitmap, rect); + ctx.DrawBitmapInRect(bitmap, rect); } } void DigitLayerInner::OnUpdate(const Pebble::GContext& ctx) { auto bounds = this->GetBounds(); - ctx.SetFillColor(GColorBlack); ctx.SetCompositingMode(GCompOpSet); for (int i = 0; i <= this->digitCount + 2 * this->extraDigits; i++) { Pebble::GRect rect(0, i * this->digitHeight, bounds.size.w, this->digitHeight);