From f4c8e4923e7b4c06dc1a941c462bb6f499651f4a Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Mon, 11 Mar 2024 23:26:12 +0200 Subject: [PATCH 1/8] lib: add Transform class and drawImageTransformed --- docs/library/display.rst | 3 + sdk/lib/lilka/src/lilka/display.cpp | 125 ++++++++++++++++++++++++++++ sdk/lib/lilka/src/lilka/display.h | 49 +++++++++++ 3 files changed, 177 insertions(+) diff --git a/docs/library/display.rst b/docs/library/display.rst index a7edeeae..5c2edf1f 100644 --- a/docs/library/display.rst +++ b/docs/library/display.rst @@ -11,3 +11,6 @@ .. doxygenclass:: lilka::Image :members: + +.. doxygenclass:: lilka::Transform + :members: diff --git a/sdk/lib/lilka/src/lilka/display.cpp b/sdk/lib/lilka/src/lilka/display.cpp index afa57033..136406eb 100644 --- a/sdk/lib/lilka/src/lilka/display.cpp +++ b/sdk/lib/lilka/src/lilka/display.cpp @@ -99,6 +99,40 @@ void Display::drawImage(Image* image, int16_t x, int16_t y) { } } +void Display::drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform) { + int16_t w = image->width; + int16_t h = image->height; + int16_t x0 = transform.matrix[0][0] * x + transform.matrix[0][1] * y; + int16_t y0 = transform.matrix[1][0] * x + transform.matrix[1][1] * y; + int16_t x1 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * y; + int16_t y1 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * y; + int16_t x2 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * (y + h); + int16_t y2 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * (y + h); + int16_t x3 = transform.matrix[0][0] * x + transform.matrix[0][1] * (y + h); + int16_t y3 = transform.matrix[1][0] * x + transform.matrix[1][1] * (y + h); + int16_t minX = min(min(x0, x1), min(x2, x3)); + int16_t minY = min(min(y0, y1), min(y2, y3)); + int16_t maxX = max(max(x0, x1), max(x2, x3)); + int16_t maxY = max(max(y0, y1), max(y2, y3)); + int16_t destWidth = maxX - minX; + int16_t destHeight = maxY - minY; + Image dest(destWidth, destHeight, 0); + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int16_t srcX = transform.matrix[0][0] * x + transform.matrix[0][1] * y; + int16_t srcY = transform.matrix[1][0] * x + transform.matrix[1][1] * y; + if (srcX >= x && srcX < x + w) { + if (srcY >= y && srcY < y + h) { + dest.pixels[x - minX + (y - minY) * destWidth] = image->pixels[srcX - x + (srcY - y) * w]; + } else { + dest.pixels[x - minX + (y - minY) * destWidth] = image->transparentColor; + } + } + } + } + drawImage(&dest, minX, minY); +} + // Чомусь в Arduino_GFX немає варіанту цього методу для const uint16_t[] - є лише для uint16_t. void Display::draw16bitRGBBitmapWithTranColor( int16_t x, int16_t y, const uint16_t bitmap[], uint16_t transparent_color, int16_t w, int16_t h @@ -138,6 +172,43 @@ void Canvas::drawImage(Image* image, int16_t x, int16_t y) { } } +void Canvas::drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform) { + int16_t w = image->width; + int16_t h = image->height; + int16_t x0 = transform.matrix[0][0] * x + transform.matrix[0][1] * y; + int16_t y0 = transform.matrix[1][0] * x + transform.matrix[1][1] * y; + int16_t x1 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * y; + int16_t y1 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * y; + int16_t x2 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * (y + h); + int16_t y2 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * (y + h); + int16_t x3 = transform.matrix[0][0] * x + transform.matrix[0][1] * (y + h); + int16_t y3 = transform.matrix[1][0] * x + transform.matrix[1][1] * (y + h); + int16_t minX = min(min(x0, x1), min(x2, x3)); + int16_t minY = min(min(y0, y1), min(y2, y3)); + int16_t maxX = max(max(x0, x1), max(x2, x3)); + int16_t maxY = max(max(y0, y1), max(y2, y3)); + int16_t destWidth = maxX - minX; + int16_t destHeight = maxY - minY; + Image dest(destWidth, destHeight, 0); + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int16_t srcX = transform.matrix[0][0] * x + transform.matrix[0][1] * y; + int16_t srcY = transform.matrix[1][0] * x + transform.matrix[1][1] * y; + if (srcX >= x && srcX < x + w) { + if (srcY >= y && srcY < y + h) { + // Піксель вихідного зображення знаходиться в межах вхідного зображення + dest.pixels[x - minX + (y - minY) * destWidth] = image->pixels[srcX - x + (srcY - y) * w]; + } else { + // Піксель вихідного зображення знаходиться поза межами вхідного зображення, + // тому він повинен бути прозорим. + dest.pixels[x - minX + (y - minY) * destWidth] = image->transparentColor; + } + } + } + } + drawImage(&dest, minX, minY); +} + void Canvas::draw16bitRGBBitmapWithTranColor( int16_t x, int16_t y, const uint16_t bitmap[], uint16_t transparent_color, int16_t w, int16_t h ) { @@ -204,6 +275,60 @@ void Image::flipY(Image* dest) { } } +Transform::Transform() : matrix{{1, 0}, {0, 1}} { +} + +// Copy constructor +Transform::Transform(const Transform& other) { + matrix[0][0] = other.matrix[0][0]; + matrix[0][1] = other.matrix[0][1]; + matrix[1][0] = other.matrix[1][0]; + matrix[1][1] = other.matrix[1][1]; +} + +// Copy assignment operator +Transform& Transform::operator=(const Transform& other) { + if (this != &other) { + matrix[0][0] = other.matrix[0][0]; + matrix[0][1] = other.matrix[0][1]; + matrix[1][0] = other.matrix[1][0]; + matrix[1][1] = other.matrix[1][1]; + } + return *this; +} + +Transform Transform::multiply(Transform other) { + // Apply other transform to this transform + Transform t; + t.matrix[0][0] = matrix[0][0] * other.matrix[0][0] + matrix[0][1] * other.matrix[1][0]; + t.matrix[0][1] = matrix[0][0] * other.matrix[0][1] + matrix[0][1] * other.matrix[1][1]; + t.matrix[1][0] = matrix[1][0] * other.matrix[0][0] + matrix[1][1] * other.matrix[1][0]; + t.matrix[1][1] = matrix[1][0] * other.matrix[0][1] + matrix[1][1] * other.matrix[1][1]; + return t; +} + +Transform Transform::rotate(int16_t angle) { + // Rotate this transform by angle. Do this by multiplying with a rotation matrix. + Transform t; + t.matrix[0][0] = fCos360(angle); + t.matrix[0][1] = -fSin360(angle); + t.matrix[1][0] = fSin360(angle); + t.matrix[1][1] = fCos360(angle); + // Apply the rotation to this transform + return t.multiply(*this); +} + +Transform Transform::scale(float sx, float sy) { + // Scale this transform by sx and sy. Do this by multiplying with a scaling matrix. + Transform t; + t.matrix[0][0] = sx; + t.matrix[0][1] = 0; + t.matrix[1][0] = 0; + t.matrix[1][1] = sy; + // Apply the scaling to this transform + return t.multiply(*this); +} + Display display; } // namespace lilka diff --git a/sdk/lib/lilka/src/lilka/display.h b/sdk/lib/lilka/src/lilka/display.h index 9bbffccf..6d33ce59 100644 --- a/sdk/lib/lilka/src/lilka/display.h +++ b/sdk/lib/lilka/src/lilka/display.h @@ -21,6 +21,7 @@ namespace lilka { class Canvas; class Image; +class Transform; /// Клас для роботи з дисплеєм. /// @@ -187,6 +188,14 @@ class Display : public Arduino_ST7789 { /// delete image; /// @endcode void drawImage(Image* image, int16_t x, int16_t y); + /// Намалювати зображення з афінними перетвореннями. + /// @param image Вказівник на зображення (об'єкт класу `lilka::Image`). + /// @param x Координата X лівого верхнього кута зображення. + /// @param y Координата Y лівого верхнього кута зображення. + /// @param transform Об'єкт класу `lilka::Transform`, який містить матрицю перетворення. + /// @note Зверніть увагу, що перетворення - це повільніше, ніж звичайне малювання зображення, оскільки обчислює координати пікселів "на льоту". Використовуйте його лише тоді, коли не можете заздалегідь створити обернені копії зображеня за допомогою методів `lilka::Image::rotate`, `lilka::Image::flipX` та `lilka::Image::flipY`. + /// @see lilka::Transform + void drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform); #ifdef DOXYGEN /// Намалювати зображення з масиву 16-бітних точок. @@ -283,6 +292,9 @@ class Canvas : public Arduino_Canvas { /// Намалювати зображення. /// @see Display::drawImage void drawImage(Image* image, int16_t x, int16_t y); + /// Намалювати зображення з афінними перетвореннями. + /// @see Display::drawImageTransformed + void drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform); void draw16bitRGBBitmapWithTranColor( int16_t x, int16_t y, const uint16_t bitmap[], uint16_t transparent_color, int16_t w, int16_t h ); @@ -335,6 +347,43 @@ class Image { uint16_t* pixels; }; +/// Клас для роботи з афінними перетвореннями. +/// +/// Афінні перетворення - це перетворення, які зберігають паралельність ліній. +/// Вони включають в себе обертання, масштабування та віддзеркалення. +/// +/// Наприклад, ось цей код обертає зображення на 30 градусів та віддзеркалює його по горизонталі: +/// +/// @code +/// lilka::Transform transform = lilka::Transform().rotate(30).flipX(); +/// lilka::display.drawImageTransformed(image, 32, 64, transform); +/// @endcode +class Transform { +public: + /// Створити об'єкт класу `lilka::Transform`. + Transform(); + Transform(const Transform& other); + Transform& operator=(const Transform& other); + /// Обернути навколо центру на кут `angle` (в градусах). + /// + /// Оскільки на екрані вісь Y вказує вниз, обертання буде здійснено за годинниковою стрілкою. + /// @param angle Кут обертання в градусах. + Transform rotate(int16_t angle); + /// Масштабувати по X та Y. + /// + /// Щоб віддзеркалити зображення, використайте від'ємні значення (наприклад, -1). + /// @param scaleX Масштаб по X. + /// @param scaleY Масштаб по Y. + Transform scale(float scaleX, float scaleY); + + /// Застосувати інше перетворення до цього. + /// @param other Інше перетворення. + Transform multiply(Transform other); + + // Матриця перетворення + float matrix[2][2]; // [рядок][стовпець] +}; + /// Екземпляр класу `Display`, який можна використовувати для роботи з дисплеєм. /// Вам не потрібно інстанціювати `Display` вручну. extern Display display; From 85313019f4e2092173a2f4643e75427c6649903a Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 00:01:23 +0200 Subject: [PATCH 2/8] keira: add transform demo --- firmware/keira/src/apps/demos/transform.cpp | 26 +++++++++++++++++++++ firmware/keira/src/apps/demos/transform.h | 11 +++++++++ firmware/keira/src/apps/launcher.cpp | 3 +++ 3 files changed, 40 insertions(+) create mode 100644 firmware/keira/src/apps/demos/transform.cpp create mode 100644 firmware/keira/src/apps/demos/transform.h diff --git a/firmware/keira/src/apps/demos/transform.cpp b/firmware/keira/src/apps/demos/transform.cpp new file mode 100644 index 00000000..821f4866 --- /dev/null +++ b/firmware/keira/src/apps/demos/transform.cpp @@ -0,0 +1,26 @@ +#include "transform.h" + +TransformApp::TransformApp() : App("Transform") { +} + +void TransformApp::run() { + lilka::Image* face = lilka::resources.loadImage("/sd/face.bmp"); + + int x = canvas->width() / 2 - face->width / 2; + int y = canvas->height() / 2 - face->height / 2; + + int angle = 0; + + while (1) { + canvas->fillScreen(canvas->color565(0, 0, 0)); + lilka::Transform transform = lilka::Transform().rotate(angle); + canvas->drawImageTransformed(face, x, y, transform); + queueDraw(); + angle++; + + lilka::State state = lilka::controller.getState(); + if (state.a.justPressed) { + return; + } + } +} diff --git a/firmware/keira/src/apps/demos/transform.h b/firmware/keira/src/apps/demos/transform.h new file mode 100644 index 00000000..2e93f71f --- /dev/null +++ b/firmware/keira/src/apps/demos/transform.h @@ -0,0 +1,11 @@ +#pragma once + +#include "app.h" + +class TransformApp : public App { +public: + TransformApp(); + +private: + void run() override; +}; diff --git a/firmware/keira/src/apps/launcher.cpp b/firmware/keira/src/apps/launcher.cpp index cc3207c7..b474b54a 100644 --- a/firmware/keira/src/apps/launcher.cpp +++ b/firmware/keira/src/apps/launcher.cpp @@ -4,6 +4,7 @@ #include "demos/lines.h" #include "demos/disk.h" #include "demos/ball.h" +#include "demos/transform.h" #include "demos/epilepsy.h" #include "demos/letris.h" #include "demos/user_spi.h" @@ -68,6 +69,7 @@ void LauncherApp::appsMenu() { String titles[] = { "Лінії", "Шайба", + "Перетворення", "М'ячик", "Епілепсія", "Летріс", @@ -80,6 +82,7 @@ void LauncherApp::appsMenu() { APP_CLASS_LIST classes = { APP_CLASS(DemoLines), APP_CLASS(DiskApp), + APP_CLASS(TransformApp), APP_CLASS(BallApp), APP_CLASS(EpilepsyApp), APP_CLASS(LetrisApp), From 7d6a61f5d6955da41d37df7a5a6c7843d9808214 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 01:45:55 +0200 Subject: [PATCH 3/8] lib: implement drawing image with affine transform, add pivot to image --- firmware/keira/src/apps/demos/transform.cpp | 21 ++- firmware/keira/src/apps/statusbar.cpp | 2 +- sdk/lib/lilka/src/lilka/display.cpp | 161 ++++++++++++-------- sdk/lib/lilka/src/lilka/display.h | 18 ++- sdk/lib/lilka/src/lilka/resources.cpp | 4 +- sdk/lib/lilka/src/lilka/resources.h | 4 +- 6 files changed, 132 insertions(+), 78 deletions(-) diff --git a/firmware/keira/src/apps/demos/transform.cpp b/firmware/keira/src/apps/demos/transform.cpp index 821f4866..f76e3a44 100644 --- a/firmware/keira/src/apps/demos/transform.cpp +++ b/firmware/keira/src/apps/demos/transform.cpp @@ -1,22 +1,31 @@ #include "transform.h" +#include + TransformApp::TransformApp() : App("Transform") { } void TransformApp::run() { - lilka::Image* face = lilka::resources.loadImage("/sd/face.bmp"); + lilka::Image* face = lilka::resources.loadImage("/sd/face.bmp", canvas->color565(0, 0, 0), 32, 32); + + int x = canvas->width() / 2; + int y = canvas->height() / 2; - int x = canvas->width() / 2 - face->width / 2; - int y = canvas->height() / 2 - face->height / 2; + Serial.println("Drawing face at " + String(x) + ", " + String(y)); int angle = 0; while (1) { - canvas->fillScreen(canvas->color565(0, 0, 0)); - lilka::Transform transform = lilka::Transform().rotate(angle); + canvas->fillScreen(canvas->color565(0, 64, 0)); + // canvas->drawImage(face, x, y); + lilka::Transform transform = lilka::Transform().rotate(angle).scale(sin(angle / 24.0), cos(angle / 50.0)); + // lilka::Transform transform = lilka::Transform().rotate(30).scale(1.5, 1); + uint64_t start = micros(); canvas->drawImageTransformed(face, x, y, transform); + uint64_t end = micros(); + Serial.println("Drawing took " + String(end - start) + " us"); queueDraw(); - angle++; + angle += 8; lilka::State state = lilka::controller.getState(); if (state.a.justPressed) { diff --git a/firmware/keira/src/apps/statusbar.cpp b/firmware/keira/src/apps/statusbar.cpp index 3f9d2075..626f14e4 100644 --- a/firmware/keira/src/apps/statusbar.cpp +++ b/firmware/keira/src/apps/statusbar.cpp @@ -37,7 +37,7 @@ void StatusBarApp::run() { canvas->draw16bitRGBBitmapWithTranColor(144, 0, wifi_offline, 0, 24, 24); } else if (networkService->getNetworkState() == NETWORK_STATE_CONNECTING) { canvas->draw16bitRGBBitmapWithTranColor(144, 0, wifi_connecting, 0, 24, 24); - } else { + } else if (networkService->getNetworkState() == NETWORK_STATE_ONLINE) { canvas->draw16bitRGBBitmapWithTranColor(144, 0, icons[networkService->getSignalStrength()], 0, 24, 24); } } diff --git a/sdk/lib/lilka/src/lilka/display.cpp b/sdk/lib/lilka/src/lilka/display.cpp index 136406eb..b4c2dd8d 100644 --- a/sdk/lib/lilka/src/lilka/display.cpp +++ b/sdk/lib/lilka/src/lilka/display.cpp @@ -93,44 +93,49 @@ void Display::setSplash(const uint16_t* splash) { void Display::drawImage(Image* image, int16_t x, int16_t y) { if (image->transparentColor == -1) { - draw16bitRGBBitmap(x, y, image->pixels, image->width, image->height); + draw16bitRGBBitmap(x - image->pivotX, y - image->pivotY, image->pixels, image->width, image->height); } else { - draw16bitRGBBitmapWithTranColor(x, y, image->pixels, image->transparentColor, image->width, image->height); + draw16bitRGBBitmapWithTranColor( + x - image->pivotX, y - image->pivotY, image->pixels, image->transparentColor, image->width, image->height + ); } } -void Display::drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform) { - int16_t w = image->width; - int16_t h = image->height; - int16_t x0 = transform.matrix[0][0] * x + transform.matrix[0][1] * y; - int16_t y0 = transform.matrix[1][0] * x + transform.matrix[1][1] * y; - int16_t x1 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * y; - int16_t y1 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * y; - int16_t x2 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * (y + h); - int16_t y2 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * (y + h); - int16_t x3 = transform.matrix[0][0] * x + transform.matrix[0][1] * (y + h); - int16_t y3 = transform.matrix[1][0] * x + transform.matrix[1][1] * (y + h); - int16_t minX = min(min(x0, x1), min(x2, x3)); - int16_t minY = min(min(y0, y1), min(y2, y3)); - int16_t maxX = max(max(x0, x1), max(x2, x3)); - int16_t maxY = max(max(y0, y1), max(y2, y3)); - int16_t destWidth = maxX - minX; - int16_t destHeight = maxY - minY; - Image dest(destWidth, destHeight, 0); - for (int y = minY; y < maxY; y++) { - for (int x = minX; x < maxX; x++) { - int16_t srcX = transform.matrix[0][0] * x + transform.matrix[0][1] * y; - int16_t srcY = transform.matrix[1][0] * x + transform.matrix[1][1] * y; - if (srcX >= x && srcX < x + w) { - if (srcY >= y && srcY < y + h) { - dest.pixels[x - minX + (y - minY) * destWidth] = image->pixels[srcX - x + (srcY - y) * w]; - } else { - dest.pixels[x - minX + (y - minY) * destWidth] = image->transparentColor; - } +void Display::drawImageTransformed(Image* image, int16_t destX, int16_t destY, Transform transform) { + // Transform image around its pivot. + // Draw the rotated image at the specified position. + + // Calculate the coordinates of the four corners of the destination rectangle. + IntVector v1 = transform.apply(IntVector(-image->pivotX, -image->pivotY)); + IntVector v2 = transform.apply(IntVector(image->width - image->pivotX, -image->pivotY)); + IntVector v3 = transform.apply(IntVector(-image->pivotX, image->height - image->pivotY)); + IntVector v4 = transform.apply(IntVector(image->width - image->pivotX, image->height - image->pivotY)); + + // Find the bounding box of the transformed image. + IntVector topLeft = IntVector(min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))); + IntVector bottomRight = IntVector(max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))); + + // Create a new image to hold the transformed image. + Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); + + // Draw the transformed image to the new image. + Transform inverse = transform.inverse(); + for (int y = topLeft.y; y < bottomRight.y; y++) { + for (int x = topLeft.x; x < bottomRight.x; x++) { + IntVector v = inverse.apply(IntVector(x, y)); + // Apply pivot offset + v.x += image->pivotX; + v.y += image->pivotY; + if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = + image->pixels[v.x + v.y * image->width]; + } else { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; } } } - drawImage(&dest, minX, minY); + + drawImage(&destImage, destX + topLeft.x, destY + topLeft.y); } // Чомусь в Arduino_GFX немає варіанту цього методу для const uint16_t[] - є лише для uint16_t. @@ -166,47 +171,50 @@ Canvas::Canvas(uint16_t x, uint16_t y, uint16_t width, uint16_t height) : void Canvas::drawImage(Image* image, int16_t x, int16_t y) { if (image->transparentColor == -1) { - draw16bitRGBBitmap(x, y, image->pixels, image->width, image->height); + draw16bitRGBBitmap(x - image->pivotX, y - image->pivotY, image->pixels, image->width, image->height); } else { - draw16bitRGBBitmapWithTranColor(x, y, image->pixels, image->transparentColor, image->width, image->height); + draw16bitRGBBitmapWithTranColor( + x - image->pivotX, y - image->pivotY, image->pixels, image->transparentColor, image->width, image->height + ); } } -void Canvas::drawImageTransformed(Image* image, int16_t x, int16_t y, Transform transform) { - int16_t w = image->width; - int16_t h = image->height; - int16_t x0 = transform.matrix[0][0] * x + transform.matrix[0][1] * y; - int16_t y0 = transform.matrix[1][0] * x + transform.matrix[1][1] * y; - int16_t x1 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * y; - int16_t y1 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * y; - int16_t x2 = transform.matrix[0][0] * (x + w) + transform.matrix[0][1] * (y + h); - int16_t y2 = transform.matrix[1][0] * (x + w) + transform.matrix[1][1] * (y + h); - int16_t x3 = transform.matrix[0][0] * x + transform.matrix[0][1] * (y + h); - int16_t y3 = transform.matrix[1][0] * x + transform.matrix[1][1] * (y + h); - int16_t minX = min(min(x0, x1), min(x2, x3)); - int16_t minY = min(min(y0, y1), min(y2, y3)); - int16_t maxX = max(max(x0, x1), max(x2, x3)); - int16_t maxY = max(max(y0, y1), max(y2, y3)); - int16_t destWidth = maxX - minX; - int16_t destHeight = maxY - minY; - Image dest(destWidth, destHeight, 0); - for (int y = minY; y < maxY; y++) { - for (int x = minX; x < maxX; x++) { - int16_t srcX = transform.matrix[0][0] * x + transform.matrix[0][1] * y; - int16_t srcY = transform.matrix[1][0] * x + transform.matrix[1][1] * y; - if (srcX >= x && srcX < x + w) { - if (srcY >= y && srcY < y + h) { - // Піксель вихідного зображення знаходиться в межах вхідного зображення - dest.pixels[x - minX + (y - minY) * destWidth] = image->pixels[srcX - x + (srcY - y) * w]; - } else { - // Піксель вихідного зображення знаходиться поза межами вхідного зображення, - // тому він повинен бути прозорим. - dest.pixels[x - minX + (y - minY) * destWidth] = image->transparentColor; - } +void Canvas::drawImageTransformed(Image* image, int16_t destX, int16_t destY, Transform transform) { + // Transform image around its pivot. + // Draw the rotated image at the specified position. + + // Calculate the coordinates of the four corners of the destination rectangle. + IntVector v1 = transform.apply(IntVector(-image->pivotX, -image->pivotY)); + IntVector v2 = transform.apply(IntVector(image->width - image->pivotX, -image->pivotY)); + IntVector v3 = transform.apply(IntVector(-image->pivotX, image->height - image->pivotY)); + IntVector v4 = transform.apply(IntVector(image->width - image->pivotX, image->height - image->pivotY)); + + // Find the bounding box of the transformed image. + IntVector topLeft = IntVector(min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))); + IntVector bottomRight = IntVector(max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))); + + // Create a new image to hold the transformed image. + Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); + + // Draw the transformed image to the new image. + Transform inverse = transform.inverse(); + for (int y = topLeft.y; y < bottomRight.y; y++) { + for (int x = topLeft.x; x < bottomRight.x; x++) { + IntVector v = inverse.apply(IntVector(x, y)); + // Apply pivot offset + v.x += image->pivotX; + v.y += image->pivotY; + if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = + image->pixels[v.x + v.y * image->width]; + } else { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; } } } - drawImage(&dest, minX, minY); + + // TODO: Draw directly to the canvas? + drawImage(&destImage, destX + topLeft.x, destY + topLeft.y); } void Canvas::draw16bitRGBBitmapWithTranColor( @@ -229,8 +237,8 @@ int16_t Canvas::y() { return _output_y; } -Image::Image(uint32_t width, uint32_t height, int32_t transparentColor) : - width(width), height(height), transparentColor(transparentColor) { +Image::Image(uint32_t width, uint32_t height, int32_t transparentColor, int16_t pivotX, int16_t pivotY) : + width(width), height(height), transparentColor(transparentColor), pivotX(pivotX), pivotY(pivotY) { // Allocate pixels in PSRAM pixels = static_cast(ps_malloc(width * height * sizeof(uint16_t))); } @@ -329,6 +337,25 @@ Transform Transform::scale(float sx, float sy) { return t.multiply(*this); } +Transform Transform::inverse() { + // Calculate the inverse of this transform + Transform t; + float det = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]; + t.matrix[0][0] = matrix[1][1] / det; + t.matrix[0][1] = -matrix[0][1] / det; + t.matrix[1][0] = -matrix[1][0] / det; + t.matrix[1][1] = matrix[0][0] / det; + return t; +} + +IntVector Transform::apply(IntVector v) { + // Apply this transform to a vector + return IntVector(matrix[0][0] * v.x + matrix[0][1] * v.y, matrix[1][0] * v.x + matrix[1][1] * v.y); +} + +IntVector::IntVector(int32_t x, int32_t y) : x(x), y(y) { +} + Display display; } // namespace lilka diff --git a/sdk/lib/lilka/src/lilka/display.h b/sdk/lib/lilka/src/lilka/display.h index 6d33ce59..823543ae 100644 --- a/sdk/lib/lilka/src/lilka/display.h +++ b/sdk/lib/lilka/src/lilka/display.h @@ -22,6 +22,7 @@ namespace lilka { class Canvas; class Image; class Transform; +class IntVector; /// Клас для роботи з дисплеєм. /// @@ -311,7 +312,7 @@ class Canvas : public Arduino_Canvas { /// @note Основна відмінність Image від поняття "bitmap" погялає в тому, що Image містить масив пікселів, розміри зображення і прозорий колір, в той час як "bitmap" - це просто масив пікселів. class Image { public: - Image(uint32_t width, uint32_t height, int32_t transparentColor = -1); + Image(uint32_t width, uint32_t height, int32_t transparentColor = -1, int16_t pivotX = 0, int16_t pivotY = 0); ~Image(); /// Обернути зображення на заданий кут (в градусах) і записати результат в `dest`. /// @@ -344,6 +345,8 @@ class Image { uint32_t height; /// 16-бітний колір (5-6-5), який буде прозорим. За замовчуванням -1 (прозорість відсутня). int32_t transparentColor; + int16_t pivotX; + int16_t pivotY; uint16_t* pixels; }; @@ -380,10 +383,23 @@ class Transform { /// @param other Інше перетворення. Transform multiply(Transform other); + /// Інвертувати перетворення. + /// @note Інвертне перетворення - це таке перетворення, яке скасує це перетворення, тобто є зворотнім до цього. + Transform inverse(); + + IntVector apply(IntVector vector); + // Матриця перетворення float matrix[2][2]; // [рядок][стовпець] }; +class IntVector { +public: + IntVector(int32_t x, int32_t y); + int32_t x; + int32_t y; +}; + /// Екземпляр класу `Display`, який можна використовувати для роботи з дисплеєм. /// Вам не потрібно інстанціювати `Display` вручну. extern Display display; diff --git a/sdk/lib/lilka/src/lilka/resources.cpp b/sdk/lib/lilka/src/lilka/resources.cpp index 06fa40eb..cb4e1111 100644 --- a/sdk/lib/lilka/src/lilka/resources.cpp +++ b/sdk/lib/lilka/src/lilka/resources.cpp @@ -5,7 +5,7 @@ namespace lilka { -Image* Resources::loadImage(String filename, int32_t transparentColor) { +Image* Resources::loadImage(String filename, int32_t transparentColor, int32_t pivotX, int32_t pivotY) { FILE* file = fopen(filename.c_str(), "r"); if (!file) { // serial_err("File not found: %s\n", filename.c_str()); @@ -37,7 +37,7 @@ Image* Resources::loadImage(String filename, int32_t transparentColor) { return 0; } - Image* image = new Image(width, height, transparentColor); + Image* image = new Image(width, height, transparentColor, pivotX, pivotY); fseek(file, dataOffset, SEEK_SET); uint8_t row[width * bytesPerPixel]; for (int y = height - 1; y >= 0; y--) { diff --git a/sdk/lib/lilka/src/lilka/resources.h b/sdk/lib/lilka/src/lilka/resources.h index 16b18c49..a9377e40 100644 --- a/sdk/lib/lilka/src/lilka/resources.h +++ b/sdk/lib/lilka/src/lilka/resources.h @@ -13,6 +13,8 @@ class Resources { /// /// \param filename Шлях до файлу. /// \param transparentColor 16-бітний колір (5-6-5), який буде прозорим. За замовчуванням -1 (прозорість відсутня). + /// \param pivotX X-координата точки, яка буде центром зображення. За замовчуванням 0. + /// \param pivotY Y-координата точки, яка буде центром зображення. За замовчуванням 0. /// \return Вказівник на зображення. /// /// \warning Пам'ять для зображення виділяється динамічно. Після використання зображення, його потрібно видалити за допомогою `delete`. @@ -32,7 +34,7 @@ class Resources { /// // Звільнити пам'ять /// delete image; /// \endcode - Image* loadImage(String filename, int32_t transparentColor = -1); + Image* loadImage(String filename, int32_t transparentColor = -1, int32_t pivotX = 0, int32_t pivotY = 0); /// Прочитати вміст файлу. /// /// TODO: Update sdcard/filesystem stuff From 86516bba66c960ccabe5fbb3e3b9ad7589526d50 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 01:47:11 +0200 Subject: [PATCH 4/8] keira: update asteroids sounds --- firmware/keira/sdcard/asteroids/asteroids.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/keira/sdcard/asteroids/asteroids.lua b/firmware/keira/sdcard/asteroids/asteroids.lua index 681fc7b0..27c0f08f 100644 --- a/firmware/keira/sdcard/asteroids/asteroids.lua +++ b/firmware/keira/sdcard/asteroids/asteroids.lua @@ -458,7 +458,7 @@ function lilka.update(delta) bullet.speed_x = ship.speed_x / 2 + display.width * dir_x bullet.speed_y = ship.speed_y / 2 + display.width * dir_y table.insert(bullets, bullet) - buzzer.play_melody(SHOOT_SOUND, 400) + buzzer.play_melody(SHOOT_SOUND, 600) end -- Вихід з гри From 8a30cdda16b961817c5aa179298d413c9f952474 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 01:50:06 +0200 Subject: [PATCH 5/8] keira: comment stuff out --- firmware/keira/src/apps/demos/transform.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/keira/src/apps/demos/transform.cpp b/firmware/keira/src/apps/demos/transform.cpp index f76e3a44..985efea5 100644 --- a/firmware/keira/src/apps/demos/transform.cpp +++ b/firmware/keira/src/apps/demos/transform.cpp @@ -20,10 +20,10 @@ void TransformApp::run() { // canvas->drawImage(face, x, y); lilka::Transform transform = lilka::Transform().rotate(angle).scale(sin(angle / 24.0), cos(angle / 50.0)); // lilka::Transform transform = lilka::Transform().rotate(30).scale(1.5, 1); - uint64_t start = micros(); + // uint64_t start = micros(); canvas->drawImageTransformed(face, x, y, transform); - uint64_t end = micros(); - Serial.println("Drawing took " + String(end - start) + " us"); + // uint64_t end = micros(); + // Serial.println("Drawing took " + String(end - start) + " us"); queueDraw(); angle += 8; From 465430451fc1bbcf26ecbbc0fe367ff93dabe8ca Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 18:05:58 +0200 Subject: [PATCH 6/8] lib: add keyboard input dialog lib: improve transformed drawing performance keira: pin all apps to core 0 keira: improve status bar icons & alignment --- Makefile | 52 +- firmware/doom/{assets => src}/doom_splash.png | Bin firmware/keira/src/app.cpp | 5 +- firmware/keira/src/apps/demos/keyboard.cpp | 27 + firmware/keira/src/apps/demos/keyboard.h | 11 + .../apps/demos}/letris_splash.png | Bin firmware/keira/src/apps/demos/transform.cpp | 10 + firmware/keira/src/apps/icons/battery.h | 502 +------- firmware/keira/src/apps/icons/battery.png | Bin 5070 -> 5290 bytes .../keira/src/apps/icons/battery_absent.h | 506 +------- .../keira/src/apps/icons/battery_absent.png | Bin 5350 -> 5351 bytes .../keira/src/apps/icons/battery_danger.h | 502 +------- .../keira/src/apps/icons/battery_danger.png | Bin 5290 -> 5284 bytes firmware/keira/src/apps/icons/ram.h | 584 ++++++++++ firmware/keira/src/apps/icons/ram.png | Bin 0 -> 4553 bytes firmware/keira/src/apps/icons/wifi_0.h | 134 +-- firmware/keira/src/apps/icons/wifi_0.png | Bin 1029 -> 4705 bytes firmware/keira/src/apps/icons/wifi_1.h | 170 +-- firmware/keira/src/apps/icons/wifi_1.png | Bin 1051 -> 4674 bytes firmware/keira/src/apps/icons/wifi_2.h | 232 ++-- firmware/keira/src/apps/icons/wifi_2.png | Bin 1090 -> 4579 bytes firmware/keira/src/apps/icons/wifi_3.h | 352 +++--- firmware/keira/src/apps/icons/wifi_3.png | Bin 1096 -> 4322 bytes firmware/keira/src/apps/icons/wifi_offline.h | 246 ++-- .../keira/src/apps/icons/wifi_offline.png | Bin 989 -> 4667 bytes firmware/keira/src/apps/launcher.cpp | 3 + firmware/keira/src/apps/statusbar.cpp | 106 +- firmware/keira/src/apps/statusbar.h | 1 + .../keira/{assets => src}/keira_splash.png | Bin .../{assets => src/lilka}/default_splash.png | Bin sdk/lib/lilka/src/lilka/display.cpp | 60 +- sdk/lib/lilka/src/lilka/display.h | 14 +- sdk/lib/lilka/src/lilka/ui.cpp | 189 +++ sdk/lib/lilka/src/lilka/ui.h | 31 + sdk/tools/image2code/ship.h | 1032 +++++++++++++++++ 35 files changed, 2767 insertions(+), 2002 deletions(-) rename firmware/doom/{assets => src}/doom_splash.png (100%) create mode 100644 firmware/keira/src/apps/demos/keyboard.cpp create mode 100644 firmware/keira/src/apps/demos/keyboard.h rename firmware/keira/{assets => src/apps/demos}/letris_splash.png (100%) create mode 100644 firmware/keira/src/apps/icons/ram.h create mode 100644 firmware/keira/src/apps/icons/ram.png rename firmware/keira/{assets => src}/keira_splash.png (100%) rename sdk/lib/lilka/{assets => src/lilka}/default_splash.png (100%) create mode 100644 sdk/tools/image2code/ship.h diff --git a/Makefile b/Makefile index 463bd88f..ecc81aef 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ +IMAGE2CODE = ./sdk/tools/image2code/image2code.py +CPPCHECK = cppcheck +CLANG_FORMAT = clang-format + help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}' -.PHONY: reformat -reformat: ## Reformat all source files - @find \ +.PHONY: todo +todo: ## Find all TODO, FIXME, XXX comments + find \ . \ -not \( -name .ccls-cache -prune \) \ -not \( -name .pio -prune \) \ @@ -16,24 +20,21 @@ reformat: ## Reformat all source files -o -iname *.hpp \ -o -iname *.h \ -o -iname *.rst \ - | xargs clang-format -i + | xargs grep --color=always -n -H -E "TODO|FIXME|XXX" \ -.PHONY: todo -todo: ## Find all TODO, FIXME, XXX comments - @find \ - . \ +.PHONY: icons +icons: + # Find all PNG images in firmware and sdk folders and convert them to .h + find \ + firmware \ + sdk \ -not \( -name .ccls-cache -prune \) \ -not \( -name .pio -prune \) \ -not \( -name mjs -prune \) \ -not \( -name doomgeneric -prune \) \ -not \( -name bak -prune \) \ - -iname *.h \ - -o -iname *.cpp \ - -o -iname *.c \ - -o -iname *.hpp \ - -o -iname *.h \ - -o -iname *.rst \ - | xargs grep --color=always -n -H -E "TODO|FIXME|XXX" \ + -iname *.png \ + -exec $(IMAGE2CODE) {} \; .PHONY: check check: clang-format cppcheck ## Run all checks @@ -61,11 +62,11 @@ clang-format: ## Run clang-format check -o -iname *.c \ -o -iname *.hpp \ -o -iname *.h \ - | xargs clang-format --dry-run --Werror + | xargs $(CLANG_FORMAT) --dry-run --Werror .PHONY: cppcheck cppcheck: ## Run cppcheck check - cppcheck . -i.ccls-cache -ipio -imjs -idoomgeneric -ibak --enable=performance,style \ + $(CPPCHECK) . -i.ccls-cache -ipio -imjs -idoomgeneric -ibak --enable=performance,style \ --suppress=knownPointerToBool \ --suppress=noCopyConstructor \ --suppress=noOperatorEq \ @@ -73,19 +74,4 @@ cppcheck: ## Run cppcheck check --error-exitcode=1 .PHONY: fix -fix: - # Find all files, but exclude .pio and .ccls-cache directories - # Preserve colors in output - find \ - . \ - -not \( -name .ccls-cache -prune \) \ - -not \( -name .pio -prune \) \ - -not \( -name mjs -prune \) \ - -not \( -name doomgeneric -prune \) \ - -not \( -name bak -prune \) \ - -iname *.h \ - -o -iname *.cpp \ - -o -iname *.c \ - -o -iname *.hpp \ - -o -iname *.h \ - | xargs clang-format -i +fix: ## Fix code style diff --git a/firmware/doom/assets/doom_splash.png b/firmware/doom/src/doom_splash.png similarity index 100% rename from firmware/doom/assets/doom_splash.png rename to firmware/doom/src/doom_splash.png diff --git a/firmware/keira/src/app.cpp b/firmware/keira/src/app.cpp index 2ade18fa..bc5ef3ed 100644 --- a/firmware/keira/src/app.cpp +++ b/firmware/keira/src/app.cpp @@ -15,6 +15,9 @@ App::App(const char* name, uint16_t x, uint16_t y, uint16_t w, uint16_t h) : backCanvas(new lilka::Canvas(x, y, w, h)), isDrawQueued(false), backCanvasMutex(xSemaphoreCreateMutex()) { + // Clear buffers + canvas->fillScreen(0); + backCanvas->fillScreen(0); Serial.println( "Created app " + String(name) + " at " + String(x) + ", " + String(y) + " with size " + String(w) + "x" + String(h) @@ -27,7 +30,7 @@ void App::start() { return; } Serial.println("Starting app " + String(name)); - if (xTaskCreate(_run, name, 8192, this, 1, &taskHandle) != pdPASS) { + if (xTaskCreatePinnedToCore(_run, name, 8192, this, 1, &taskHandle, 0) != pdPASS) { Serial.println("Failed to create task for app " + String(name) + " (not enough memory?)"); } } diff --git a/firmware/keira/src/apps/demos/keyboard.cpp b/firmware/keira/src/apps/demos/keyboard.cpp new file mode 100644 index 00000000..6f81327f --- /dev/null +++ b/firmware/keira/src/apps/demos/keyboard.cpp @@ -0,0 +1,27 @@ +#include "keyboard.h" + +KeyboardApp::KeyboardApp() : App("Keyboard") { +} + +void KeyboardApp::run() { + lilka::InputDialog dialog("Введіть текст:"); + + while (true) { + dialog.update(); + dialog.draw(canvas); + queueDraw(); + if (dialog.isDone()) { + break; + } + } + + lilka::Alert alert("Ви ввели:", dialog.getValue()); + alert.draw(canvas); + queueDraw(); + while (true) { + alert.update(); + if (alert.isDone()) { + break; + } + } +} diff --git a/firmware/keira/src/apps/demos/keyboard.h b/firmware/keira/src/apps/demos/keyboard.h new file mode 100644 index 00000000..d194eb41 --- /dev/null +++ b/firmware/keira/src/apps/demos/keyboard.h @@ -0,0 +1,11 @@ +#pragma once + +#include "app.h" + +class KeyboardApp : public App { +public: + KeyboardApp(); + +private: + void run() override; +}; diff --git a/firmware/keira/assets/letris_splash.png b/firmware/keira/src/apps/demos/letris_splash.png similarity index 100% rename from firmware/keira/assets/letris_splash.png rename to firmware/keira/src/apps/demos/letris_splash.png diff --git a/firmware/keira/src/apps/demos/transform.cpp b/firmware/keira/src/apps/demos/transform.cpp index 985efea5..aec0b0c4 100644 --- a/firmware/keira/src/apps/demos/transform.cpp +++ b/firmware/keira/src/apps/demos/transform.cpp @@ -8,6 +8,16 @@ TransformApp::TransformApp() : App("Transform") { void TransformApp::run() { lilka::Image* face = lilka::resources.loadImage("/sd/face.bmp", canvas->color565(0, 0, 0), 32, 32); + if (!face) { + lilka::Alert alert("Помилка", "Не вдалось завантажити face.bmp з SD-карти."); + alert.draw(canvas); + queueDraw(); + while (!alert.isDone()) { + alert.update(); + } + return; + } + int x = canvas->width() / 2; int y = canvas->height() / 2; diff --git a/firmware/keira/src/apps/icons/battery.h b/firmware/keira/src/apps/icons/battery.h index ef446e51..8f0f7992 100644 --- a/firmware/keira/src/apps/icons/battery.h +++ b/firmware/keira/src/apps/icons/battery.h @@ -1,7 +1,7 @@ // This is a generated file, do not edit. // clang-format off #include -const uint16_t battery_width = 32; +const uint16_t battery_width = 16; const uint16_t battery_height = 24; const uint16_t battery[] = { 0xf81f, @@ -42,6 +42,10 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, + 0xffff, + 0xffff, + 0xffff, + 0xffff, 0xf81f, 0xf81f, 0xf81f, @@ -53,172 +57,6 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, @@ -232,6 +70,7 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, + 0xf81f, 0xffff, 0xffff, 0xffff, @@ -242,6 +81,11 @@ const uint16_t battery[] = { 0xffff, 0xffff, 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, 0xffff, 0xffff, 0xffff, @@ -254,12 +98,6 @@ const uint16_t battery[] = { 0xffff, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, @@ -274,28 +112,12 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0xffff, 0xffff, 0xf81f, 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xffff, 0xffff, 0xffff, 0x0000, @@ -306,20 +128,6 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0xffff, 0xffff, 0xf81f, @@ -328,14 +136,6 @@ const uint16_t battery[] = { 0xf81f, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -344,6 +144,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -360,14 +168,6 @@ const uint16_t battery[] = { 0xf81f, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -376,6 +176,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -392,14 +200,6 @@ const uint16_t battery[] = { 0xf81f, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -408,6 +208,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -424,14 +232,6 @@ const uint16_t battery[] = { 0xf81f, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -440,6 +240,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -454,8 +262,6 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xffff, 0xffff, 0xffff, 0x0000, @@ -466,12 +272,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -486,8 +294,6 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, 0xffff, 0xffff, 0x0000, @@ -498,12 +304,14 @@ const uint16_t battery[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xffff, + 0xffff, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -518,11 +326,6 @@ const uint16_t battery[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xffff, - 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, @@ -535,27 +338,11 @@ const uint16_t battery[] = { 0xffff, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xffff, - 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, @@ -566,177 +353,6 @@ const uint16_t battery[] = { 0xffff, 0xffff, 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, diff --git a/firmware/keira/src/apps/icons/battery.png b/firmware/keira/src/apps/icons/battery.png index 4b0e48e0ea23e5f851d45d1814f31ed5cafdbc12..5892d729e5d7cbae43fe3b9903160ffcc83cde21 100644 GIT binary patch delta 743 zcmX@7zDiTEGr-TCmrII^fq{Y7)59eQNDBb51P2?C{Jfx+XQHAMqrgO)U`D2i6P$T< z7#SFVhyhGbd?3YXq+n=jWo&L`IGLHzN_*|8%jbX!nlqi913aCb6$*;-(=u~X85k<& z)K0YZIP4&EG(LE#lCJCL^p}5^D}T?hFf@7A)#)rIcg;4xoH9dy zP1nM37C|?bLYLGu$>K><8sGoe<=(KqoO9mO`gi9A1G~kTnUo4ANiOr<<7l%vQ+m$# z&g3;ptB*WCBCHlW;m5?+UB~n1oYv#EF;087>GKi8q>XnDd+~4XS}Eu+d_2^5d5z-x z`i-Y5yElhrZ#ZZBll!o1ZR*U|ChilDDNR#wY-wU!wc?;#Q`lS)?#NsIKYzH#?03;? zjR`d<(pkXAyXiIi|K|I5qn57p)YqKD^ebNGc`^^jTc)?m9@ofQ`~7C&uwxFdx*ng; zxOx5(^W9N@I6Cr}#jnTu-elG*Z+NKgY?d0%b;(l1OZCCuo_#ABc2d0*xbKzU9rE-4&wKghJ9DyB(Sox-IiE8y2(oOx%GAZAVs36~lxksU zplfJhWUOnFW@@QxVPa{an`)kBW?-6{WN46PJh_>51&@)bftj(nftiVkg~?=dwn9#$ z5LmQrWK%`(Hs5F4%{+NKXN-!Op-D=biJ7UcVUnS_u8EPQxvpiZfw69iiBW2bajHdf znn}{+LJlu(L%31qn|rwOIK=KglsgYhA#6$B?k+$Y2!1;6uAeL*tiZv;t17rrZ))OX z3t^3nU{4pv5R21qrx@}vC~z=qe*7Q5Zg+=+M9d3~g)v?%B0*9?nOQrhPUaS6QoGON zIE78OciHT@j%v&d@9!mNzSZqHDACjSSvt~YqSV|qs~-qHaAuQc;1Mv|P{p4Gvenbo K&t;ucLK6V>xC;3I delta 720 zcmZ3bc}`uiGr-TCmrII^fq{Y7)59eQNGkxb1P2?CoE`k%WTK)Jqrya+U`FPN6P$Vf zXfiNF17*PU#0OHG1`39zR)!W<#*>*Dt+cCbqhuHu7+W%(odZ0bofQg-^3yVNQW+R3 z=G0EK^*HPxb2L79X;2i4uEyjHM$>w+s3R2xclyh}%ay-pSQwZ%>#8uj$z8L{CtGHm zUE9?d{zK43f>~nH%+xcUL0t15zm~JxckgJ$wC_9Z-6PIM^L*$$QkXWw>?7O9Gs|)d z?y2`}n6yS{zOes{630jG>$G+29>ps~3xVtuV#;hFGRw0M?-H&T}7#m|3M3&EapL{%X9>c%%2VU=g ztmaMlHu+1Hd$%0p-`fX{mbwRjYd9^N@Z;nJ-_w&OgQ2yxpN-?bYaN z`Q`i$ZM(egGO)KFsF=9vy6wHY*YDompMLA_Uj|pcqAA&Pc3Chm2qPTT{ysO%FL{i3NQA`Q-vpviwcTg_ uz{<=i@O8`e9kLx84$Nh=a%Qe!xxk>YgU?v`bAThzW(H4JKbLh*2~7YJLKqPM diff --git a/firmware/keira/src/apps/icons/battery_absent.h b/firmware/keira/src/apps/icons/battery_absent.h index 3797e451..a3df7842 100644 --- a/firmware/keira/src/apps/icons/battery_absent.h +++ b/firmware/keira/src/apps/icons/battery_absent.h @@ -1,7 +1,7 @@ // This is a generated file, do not edit. // clang-format off #include -const uint16_t battery_absent_width = 32; +const uint16_t battery_absent_width = 16; const uint16_t battery_absent_height = 24; const uint16_t battery_absent[] = { 0xf81f, @@ -42,6 +42,10 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, + 0xad55, + 0xad55, + 0xad55, + 0xad55, 0xf81f, 0xf81f, 0xf81f, @@ -53,172 +57,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, 0xad55, 0xad55, 0xad55, @@ -232,6 +70,7 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, + 0xf81f, 0xad55, 0xad55, 0xad55, @@ -242,6 +81,11 @@ const uint16_t battery_absent[] = { 0xad55, 0xad55, 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, 0xad55, 0xad55, 0xad55, @@ -254,12 +98,6 @@ const uint16_t battery_absent[] = { 0xad55, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, @@ -273,20 +111,6 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0x0000, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0xad55, 0xad55, @@ -294,8 +118,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xad55, 0xad55, 0xad55, 0x0000, @@ -307,10 +129,12 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, 0xad55, 0x0000, 0x0000, @@ -329,10 +153,6 @@ const uint16_t battery_absent[] = { 0xad55, 0xad55, 0xad55, - 0xad55, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -340,17 +160,21 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0xad55, - 0x0000, - 0x0000, + 0xad55, + 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, 0xad55, 0x0000, + 0xad55, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xad55, 0x0000, 0xad55, 0xad55, @@ -360,27 +184,27 @@ const uint16_t battery_absent[] = { 0xf81f, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, + 0xad55, 0x0000, 0x0000, + 0xad55, 0x0000, 0x0000, 0xad55, 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, + 0xad55, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xad55, + 0xad55, 0x0000, 0x0000, 0x0000, @@ -392,15 +216,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -409,13 +224,6 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0xad55, 0xad55, 0xf81f, @@ -424,15 +232,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0xad55, @@ -441,12 +240,21 @@ const uint16_t battery_absent[] = { 0xad55, 0x0000, 0x0000, + 0xad55, + 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, + 0xad55, 0x0000, + 0xad55, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, + 0xad55, 0x0000, 0xad55, 0xad55, @@ -454,7 +262,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, 0xad55, 0xad55, 0xad55, @@ -464,13 +271,14 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xad55, + 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, 0xad55, 0x0000, 0x0000, @@ -486,8 +294,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, 0xad55, 0xad55, 0x0000, @@ -497,14 +303,16 @@ const uint16_t battery_absent[] = { 0x0000, 0x0000, 0x0000, - 0xad55, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0xad55, + 0xad55, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xad55, + 0xad55, + 0x0000, 0x0000, 0x0000, 0x0000, @@ -518,9 +326,6 @@ const uint16_t battery_absent[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xad55, 0xad55, 0xad55, 0xad55, @@ -533,27 +338,11 @@ const uint16_t battery_absent[] = { 0xad55, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xad55, 0xad55, 0xad55, 0xad55, @@ -564,179 +353,6 @@ const uint16_t battery_absent[] = { 0xad55, 0xad55, 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xad55, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, diff --git a/firmware/keira/src/apps/icons/battery_absent.png b/firmware/keira/src/apps/icons/battery_absent.png index 3976b5e6130ef6dd72e3fbbca8d86ca3c3330589..b7825e64e22a7e854013bbda70867d4368fa5a6e 100644 GIT binary patch delta 875 zcmaE+`CL=6Gr-TCmrII^fq{Y7)59eQNDBb51P2?C{Jfx+XQHAMqrgO)U`D2i6P$T< z7#SFVhyhGbd?3YTq+n=jWo&L`YC4&P(XyWB(4~Js70sE>&HM}a>Kg=GanB@>1IPZxQ>Yqt62lo|SK zx)#=lvk1De6uP9QNfu9<()j+zF87A@<(%`L*1tP17}zbw%%oH}NphL*9!HzanbLE< zcP6hQTjd9wuO`ne#CT+ZP*o%L2*GfTu;p3sc%WD+h zZ#-4my*Vs-c7IB|2N;i8?|($r@rPKreEXS39Bu1g|bst^A5>|4pebC;<(J1&22?HoG> z%U4>(%rY`ek5k1?#eJ{*?vS7Vf8NV4-!D|n1d4b03o6kW^26mwm3YAPodRop;v*Db50q$YKTtJ!KGPtXOJa1{7p3@$_|N zf5FVdt7@LCEHG!Xw1`Ii1Wy;o5R21CLp=EoC~&x3(m$pAapJcWXUzp}(mOQ`B->O& zSBQ%7Bwo}zAGl-By_ugZnCHIv%gCUzvQd1A@1}z{Q)GW%Z0ItBXhN$1Gr-TCmrII^fq{Y7)59eQNGkxb1P2?CoE`k%WTK)Jqrya+U`FPN6P$Vf zXfiNF17*PU#0OGb1`39zRz{{)#s-sF7%l6?n;hjB7#LeJot*>O*gE}z-Qvf$;kiJq!Q zW9mYA>h~P#S2)y>6qA-#>o@7r2buWqA3lE7JGXhy`M;KjvJR#+_^bGB*p(=lFK|95 zs`T9NBZ6VmLLU`B;%wIQ_;aH4=u`7^s_m@vBn>ystbD|=G2&I?()P%k7dn=ACa+o+ zyl+Br$oH=#R8hyZhmb3fAD?Y*+*BF%og!t`m4X~uOSypS!3DdZTtIkch@rgnBSZWI?vU0=PYdcpSX_2)}|{bp=EQ?xE1^v#6L7nu5(R8o!1Q!Uey zlXa8Q%nfx-3@lT1lZ?|$bd!?Pl8us$)6C4w(k3^tuHZ2+H#amkFgGzbH!+=T##YE> z5CV_ojch7N+|Bpd#8^~-%8XJilTvgIEG!IkO)OKBbS(`GO?6XE&CJYA&CE?KED|Rd zaCl8_;9_G1Czj25+<6>!>+Vil2uw_DN#5=*4F5rJ!QSPQfg+p*9+AZi40_5S%viD1 zz6>bHUgGKN%Kn0xi&s*voO9jf$xcd2>pU|M~&y0^njP|&7fW@6l_t2SQ_ zym;IBqU=J)jtr;Vm(?ATg&#S$2pB)Q|DJj4n-juX4d3#!j@<8Ax$1xhi_smPmiNya sWqVat?9G{Q>q%eOn_MNMhWpGh`7Um{Yy3PFfbM1RboFyt=akR{0812JcK`qY diff --git a/firmware/keira/src/apps/icons/battery_danger.h b/firmware/keira/src/apps/icons/battery_danger.h index a36ea3d5..b7e13249 100644 --- a/firmware/keira/src/apps/icons/battery_danger.h +++ b/firmware/keira/src/apps/icons/battery_danger.h @@ -1,7 +1,7 @@ // This is a generated file, do not edit. // clang-format off #include -const uint16_t battery_danger_width = 32; +const uint16_t battery_danger_width = 16; const uint16_t battery_danger_height = 24; const uint16_t battery_danger[] = { 0xf81f, @@ -42,6 +42,10 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, + 0xf800, + 0xf800, + 0xf800, + 0xf800, 0xf81f, 0xf81f, 0xf81f, @@ -53,172 +57,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, 0xf800, 0xf800, 0xf800, @@ -232,6 +70,7 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, + 0xf81f, 0xf800, 0xf800, 0xf800, @@ -242,6 +81,11 @@ const uint16_t battery_danger[] = { 0xf800, 0xf800, 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, 0xf800, 0xf800, 0xf800, @@ -254,12 +98,6 @@ const uint16_t battery_danger[] = { 0xf800, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, @@ -274,28 +112,12 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0xf800, 0xf800, 0xf81f, 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf800, 0xf800, 0xf800, 0x0000, @@ -306,20 +128,6 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0xf800, 0xf800, 0xf81f, @@ -328,14 +136,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -344,6 +144,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -360,14 +168,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -376,6 +176,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -392,14 +200,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -408,6 +208,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -424,14 +232,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, @@ -440,6 +240,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -454,8 +262,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf800, 0xf800, 0xf800, 0x0000, @@ -466,12 +272,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -486,8 +294,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, 0xf800, 0xf800, 0x0000, @@ -498,12 +304,14 @@ const uint16_t battery_danger[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xf800, + 0xf800, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf81f, + 0xf800, + 0xf800, 0x0000, 0x0000, 0x0000, @@ -518,11 +326,6 @@ const uint16_t battery_danger[] = { 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf81f, - 0xf800, - 0xf800, - 0xf800, 0xf800, 0xf800, 0xf800, @@ -535,27 +338,11 @@ const uint16_t battery_danger[] = { 0xf800, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, - 0xf81f, - 0xf800, - 0xf800, - 0xf800, 0xf800, 0xf800, 0xf800, @@ -566,177 +353,6 @@ const uint16_t battery_danger[] = { 0xf800, 0xf800, 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf800, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, - 0xf81f, 0xf81f, 0xf81f, 0xf81f, diff --git a/firmware/keira/src/apps/icons/battery_danger.png b/firmware/keira/src/apps/icons/battery_danger.png index 5c89db5c446513a14e8e4b5241a8f318bd4a4667..e4094f1a9b4c6dc911025c35bb244d198c226e6f 100644 GIT binary patch delta 698 zcmZ3bxkOX3Gr-TCmrII^fq{Y7)59eQNDBb51P2?C{Jfx+XQHAMqrgO)U`D2i6P$T< z7#SFVhyhGbd?3YXq+n=jWo&L`Jeir%ibYYXGiI_QqaxcQTjd9wuO`ne#CT+ZP*o%L2*GfTu;p3sc%WD+hZ#-4my*Vs< z!#UfZ+=pFjQ)j+5ai4fhX_|s#OB36w`V|M=n!@Iaa7W(q|M|l`X1|MGYfPv?k z-c7IB|2N;i8?|($r@rPKreEXS39Bu1g|bst^A5>|4pebC;<(J1&22?HoG>%U4>(%rY`e zkHu3@#eJ{*?vS7Vf8NV4-g-DFEk6Z0gaR6|o!gUL;-D|n1d4b038Oiav8%`7LIu@!O}g}?%S1Dh&>xA`8M zIE#v@QF5A5s;Pypv7wQfu8DD?p{|8-nz^oFnt76OVv?b8s!8JH0uC>3Lzpop2AlJ^ z^Em9{X4NeP#xGlvx4R3F27;f?yX%1zXMsm#F$061G6*wPEVVBK3bL1Y`ns~eVCLaf z)p(~Zn>krZL?g-9)5S5w;`H0e2l*HbSe!%u{MRr4KC{QO>`~i_>0ALGnJr$%I(dnw zBNZJsJ>w`~Y+HQs&xgv1PaTrgZ-q-V3Q9CSkpAfxAeriN;J=(susD~+{HN?SAg6e` L`njxgN@xNADNFSm delta 702 zcmZ3Yxk^*9Gr-TCmrII^fq{Y7)59eQNGkxb1P2?CoE`k%WTK)Jqrya+U`FPN6P$Vf zXfiNF17*PU#0OHG1`39zRz@aPMw6KttynBp)OSyIWK?8x)zsxH)0mvW7+lZ1o1(eg z%&q<;-q!u=l+pFfKBZn)9mggPR^E{Mz~)|-wN{#9o3_mV^s#?OU1to}&Q%FdA{=C; zQm*s=W8c4ft5@*kxF8GGFZ(Ud9hWfJz`bR5-{;yl7H@?We(=P+jIH0xdZupDy*F7O zl@l_gckFnVbxN*aC-aecJU6GrYI+1~Ol|mX{A(GLK@E4ywLSN&ep}Qs6kQ2@#%5u` za!ma6l)djhzdLyE-ap&RFW<9UtSstZHAA*(^980pCKa>P6qD4HBokeuRP!WV6N{u2 zU5k_?OI@I#Sz4lDim{P-^5iDg6+8y!<_2b#rWVG=#zvFP*a|rfLSO;EflU>`+kB5r zoJGYrDJjh~#l%9_%+k +const uint16_t ram_width = 24; +const uint16_t ram_height = 24; +const uint16_t ram[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; +// clang-format on diff --git a/firmware/keira/src/apps/icons/ram.png b/firmware/keira/src/apps/icons/ram.png new file mode 100644 index 0000000000000000000000000000000000000000..e7f26dee84d1e27d7c01c521663660375428769d GIT binary patch literal 4553 zcmeHLe{dAl9p6hLq}K!ys8T`L*-#pYd%L&0celH}1HxUBTjA(6xnhVFySMu`*(P_p zx!cQKLV-*atkVuy#ZhalOpCOlrGryOG^60u0BvJ+##aBZSOg0=)xlIMIJKqU-Mjpn zI@8It{Fl9X_rCky_xpL@@8^BrcW>{$_=cux_swn$!>Xldq#62!cB`BP->37TE6}}; zS|v@AR$`TK1DdW1%w_99b4`-VT;*6fjO~Or4`f@%Za2HGbNU~Eyr?Aa0lBuMW7~LL zWmq-zgU}d|7eIdintpF_t(QQyuS(}*J2e~HSl=YY;yB~+(jL|i_B6wZG%I=;-0Kq= z5PYz{Ywv_dHqvOdFAo0Qt%t*LDICVljG^gW2*V14TYnge{(8;g;k#O%B*-}%=XRfr zKmNg)n|8JBAQF{_*FHUG`NP}lAKbZYc=#J8$zM6tnlroK{Nu~toLjMa&EPGA3+~+a z%GIyzxY4_0@#V9pUOaK?Yil|Zk7&79%YKx8?0t3Z$hnQfuh$J!)(p7T|7L_aw`|3A ze;&>4#_qa!CiuIne|nd!PC ztXp!l+w;P$AC3I{QR%h$P4^8aXV={_a@+pKptQKf_xRs-Jab~@dGhydPabc({2oLm+*`n^YT=T8_^wsa4U7Gplyyq8W9(wuYq5hTJ$%9Kj zyM9}~^GnN*zqrpVyRfZ$aQ6-PufE9rb=SvRKj2@Tk6)?!*88dLhg~DzePFZEd8lTu zvFON=bmwoEn9rA2t@`q_D~6iy-yg5VF1BBa345>Jc;U{E`#L{7d&zY&e*064PM@B; zkZk_sh1Z6*h+F<~dHvHzmktIp&*^u(a|FZY+@U90t=8CjQ87{;Sv8W#Q%ITieqq7Y z1yfc!k%cEwyPgga7l)1#xUPnX+kG)QW`|n5r5kD7#*~vr z&I%C(%;RJJrOa4t96p^bu>gEf1=*y$9-2y}sL2*ttDy%#N)COlMK;lEBB~i>ja)`S z4LvAr)l7y^m2rDBm+5lCQ56bxp%kcQVO8&xCG7(@ZedfuM00;wR@M{)}9Ck4OPPb#cmO(s>I zqy54ph_7dK$V$0uvR5{g3Q&y9COJm-lS!n4H=I``WtNdipP+EOf@C(J@eY)#h>b=j zCBt^=DY+d{X1d*(un8CI<5GxVJoLm!yi2w;FbEOr^>nTWDJ zj*}`|azwTefR2~p#8?@wqZyGdx^Kh93{}^9|C_dbc<>8mQ3+gW3 z6>qzA=P2R0b0|bvDTa`hdywk*30TD`r9)1)Bd8vwbR8SlKQ9$%FAd!Bq|9ppk`w48 z$@?^x{~f#LZ8$!fCZ^D11D_Mxdx|L-B%k7obW5QCIm z7RNRRCu4yqaE#;Z)`oGcTo_J$KY51X+hxft8#4p~2cgb1FbxjfHtrGh*JhUC8FPPCy zS@;j+ExWna);?B%!P%A+YnXkZysG-9xpkXH?LRi|ks|ep=!p;ayzM@QSB2+~UfnKi zxqr@cy-M4{k%8;opDcWP4_0yFdl>#H9bMj^+PE_$9uxeh@5ZF_2XeG_1)Y0?z#hQx1HL0Y~N}(l}$C(hoAb{K>25Ebookd&5#{|)UY9PaP7AT{tfqq0*(Lx literal 0 HcmV?d00001 diff --git a/firmware/keira/src/apps/icons/wifi_0.h b/firmware/keira/src/apps/icons/wifi_0.h index a0a90362..c43888d5 100644 --- a/firmware/keira/src/apps/icons/wifi_0.h +++ b/firmware/keira/src/apps/icons/wifi_0.h @@ -35,6 +35,16 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -47,6 +57,8 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -57,6 +69,8 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -65,22 +79,8 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x10a2, @@ -95,14 +95,14 @@ const uint16_t wifi_0[] = { 0x1082, 0x0020, 0x0000, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x0000, 0x0020, 0x18e3, @@ -121,11 +121,11 @@ const uint16_t wifi_0[] = { 0x18e3, 0x0020, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x0020, 0x18e3, 0x2945, @@ -146,11 +146,11 @@ const uint16_t wifi_0[] = { 0x2945, 0x18e3, 0x0020, + 0xffff, 0x0000, 0x0000, 0x0000, - 0x0861, - 0x2124, + 0xffff, 0x2945, 0x2945, 0x2945, @@ -169,12 +169,12 @@ const uint16_t wifi_0[] = { 0x2945, 0x2945, 0x2945, - 0x2124, - 0x0841, + 0xffff, 0x0000, 0x0000, - 0x18e3, - 0x2945, + 0x0000, + 0x0000, + 0xffff, 0x2945, 0x2945, 0x2104, @@ -193,13 +193,13 @@ const uint16_t wifi_0[] = { 0x2104, 0x2945, 0x2945, - 0x2945, - 0x18e3, + 0xffff, 0x0000, 0x0000, - 0x18e3, - 0x2945, - 0x2945, + 0x0000, + 0x0000, + 0x0000, + 0xffff, 0x18c3, 0x0000, 0x0861, @@ -216,15 +216,15 @@ const uint16_t wifi_0[] = { 0x0841, 0x0000, 0x18c3, - 0x2945, - 0x2945, - 0x18e3, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, + 0x0000, 0x18c3, 0x2945, 0x2945, @@ -240,6 +240,7 @@ const uint16_t wifi_0[] = { 0x2945, 0x10a2, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -247,8 +248,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x10a2, + 0xffff, 0x2945, 0x2945, 0x2945, @@ -263,7 +263,7 @@ const uint16_t wifi_0[] = { 0x2945, 0x2945, 0x2945, - 0x10a2, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -272,8 +272,8 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x18e3, - 0x2945, + 0x0000, + 0xffff, 0x2945, 0x2945, 0x10a2, @@ -286,8 +286,7 @@ const uint16_t wifi_0[] = { 0x10a2, 0x2945, 0x2945, - 0x2945, - 0x18e3, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -298,6 +297,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0861, @@ -310,6 +310,7 @@ const uint16_t wifi_0[] = { 0x0841, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -321,8 +322,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x10a2, 0x2945, 0x2945, @@ -333,6 +333,7 @@ const uint16_t wifi_0[] = { 0x2945, 0x2945, 0x10a2, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -345,8 +346,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x18e3, 0x2945, 0x2945, @@ -357,6 +357,7 @@ const uint16_t wifi_0[] = { 0x2945, 0x2945, 0x18e3, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -370,6 +371,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -378,6 +380,7 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -393,16 +396,14 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x0000, 0x5acb, 0xad55, 0xad55, 0x5acb, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -419,14 +420,14 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xffff, 0x7bef, 0xffdf, 0xffff, 0xffff, 0xf7be, 0x7bef, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -444,13 +445,12 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0xe73c, 0xffff, 0xffff, 0xffff, 0xffff, - 0xe71c, + 0xffff, + 0xffff, 0x0000, 0x0000, 0x0000, @@ -469,12 +469,13 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0xffdf, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffdf, + 0xffff, + 0xffff, + 0x0000, 0x0000, 0x0000, 0x0000, @@ -493,12 +494,10 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0xe73c, 0xffff, 0xffff, 0xffff, 0xffff, - 0xe71c, 0x0000, 0x0000, 0x0000, @@ -517,12 +516,12 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x7bef, - 0xf7be, + 0x0000, + 0x0000, + 0xffff, + 0xffff, 0xffff, 0xffff, - 0xf7be, - 0x7bef, 0x0000, 0x0000, 0x0000, @@ -542,10 +541,11 @@ const uint16_t wifi_0[] = { 0x0000, 0x0000, 0x0000, - 0x52aa, - 0xad55, - 0xad55, - 0x52aa, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0x0000, 0x0000, 0x0000, 0x0000, diff --git a/firmware/keira/src/apps/icons/wifi_0.png b/firmware/keira/src/apps/icons/wifi_0.png index dd4a2e78da2db2d1baf75506a48385469c451c91..a9a8c9d818e0d12e96e5c2fd88e1ba14ae7bf38d 100644 GIT binary patch literal 4705 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 UnCoY&_&EX>4Tx04R}tkv&MmKpe$iQ^g_`1v7{^ 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 delta 985 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 delta 1030 zcmV+h1o`{oA;<`jBYy#eX+uL$Nkc;*aB^>EX>4Tx04R}tkv&MmKpe$iTg9Rk2Q!E` zWT@g`7Zq`=RVYG*P%E_RU~=gfG-*guTpR`0f`cE6RRhT)2yyIpy{@mPA0@`ZdL4gMF?RC7=K5f%q(M0l2Y&;U-t;` z^)AM<{LlS4`qjL}fPhFGXNGALZxGLH+6L!+Vu6)pmH3=^!lVllKXP61_>FVXp|*19KuVI;4wEOVXa2$ERD5+sOF zP(v9N*oe`plYe3%P5TKS|FG+q$fc003`ULxRG~q3{osG_yIZR;HR&Zq5;acMz|fN+o3bl~Xa)-f z;QfrgDF+PR0=;WqZ>@ctJ^&f&Ds=-K90FrS%3k+*cM-U=w|~#H`uhQDopPhvj4$Am z5fCze2oxwHC&h)50006-NklC5z6oy~5n{x$0N~a9gMe#5A2P{f)bQ5&w z=AteYT>Jx8T#}&_ETZ7#ATBDk4x%8PDwY-$q#d-;MBfgV>#bTfz0?=ZkT2gkPjXK3 zemVfe0j0-*b#TDZwi_;&3m%ULcDo&Bvl&KzqY*}<5e9<+vMl5M{T;nt5A}K-nM?+) zR%#S<1yRqHY=5X3M-Wg+wC^T3WBha zC

2N#bNO`L6HV0qYSChuLg4`S$ikMNz0I3P+<6@9*zo!1={eJ)V0N>fgbUM`p&~%~=hr^Av!C>%vM`kLOf-K9+ zYgv|;R=iJ|KU1&Qi}Uky06;dI#qI6w?*jf;pExJ>zH{$)p8x;=07*qoM6N<$g1;N% ArT_o{ diff --git a/firmware/keira/src/apps/icons/wifi_offline.h b/firmware/keira/src/apps/icons/wifi_offline.h index c49f2e9f..2f255698 100644 --- a/firmware/keira/src/apps/icons/wifi_offline.h +++ b/firmware/keira/src/apps/icons/wifi_offline.h @@ -35,6 +35,16 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -47,6 +57,8 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, + 0xa800, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -57,6 +69,8 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, + 0xa800, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -65,22 +79,8 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xa800, + 0xa800, 0x0000, 0x1000, 0x4000, @@ -95,14 +95,14 @@ const uint16_t wifi_offline[] = { 0x4000, 0x1000, 0x0000, + 0xa800, + 0xa800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xa800, 0x0000, 0x2000, 0x5000, @@ -121,11 +121,11 @@ const uint16_t wifi_offline[] = { 0x5000, 0x2000, 0x0000, + 0xa800, 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xa800, 0x1800, 0x5000, 0x6800, @@ -146,11 +146,11 @@ const uint16_t wifi_offline[] = { 0x6800, 0x5000, 0x1800, + 0xa800, 0x0000, 0x0000, 0x0000, - 0x2000, - 0x6000, + 0xa800, 0x6800, 0x6800, 0x6800, @@ -169,12 +169,12 @@ const uint16_t wifi_offline[] = { 0x6800, 0x6800, 0x6800, - 0x6000, - 0x2000, + 0xa800, 0x0000, - 0x2800, - 0x6000, - 0x6800, + 0x0000, + 0x0000, + 0x0000, + 0xa800, 0x6800, 0x6800, 0x5800, @@ -193,13 +193,13 @@ const uint16_t wifi_offline[] = { 0x6000, 0x6800, 0x6800, - 0x6800, - 0x6000, - 0x2800, - 0x6000, - 0x6800, - 0x6800, - 0x6800, + 0xa800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xa800, 0x4800, 0x0000, 0x0000, @@ -216,14 +216,14 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x4800, - 0x6800, - 0x6800, - 0x6800, - 0x6000, - 0x6000, - 0x6800, - 0x6800, - 0x3000, + 0xa800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -240,16 +240,16 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x3000, - 0x6800, - 0x6800, - 0x6000, - 0x2000, - 0x4800, - 0x2000, + 0xa800, + 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, + 0x0000, + 0xa800, + 0x0000, 0x2000, 0x5800, 0x6800, @@ -263,17 +263,17 @@ const uint16_t wifi_offline[] = { 0x5800, 0x2000, 0x0000, + 0xa800, 0x0000, 0x0000, - 0x2000, - 0x4800, - 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x2800, + 0x0000, + 0x0000, + 0xa800, 0x6000, 0x6800, 0x6800, @@ -286,7 +286,7 @@ const uint16_t wifi_offline[] = { 0x6800, 0x6800, 0x6000, - 0x2800, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -296,8 +296,8 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x2000, - 0x6800, + 0x0000, + 0xa800, 0x6800, 0x6800, 0x6800, @@ -310,8 +310,7 @@ const uint16_t wifi_offline[] = { 0x6800, 0x6800, 0x6800, - 0x6800, - 0x2000, + 0xa800, 0x0000, 0x0000, 0x0000, @@ -320,9 +319,10 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x4800, - 0x6800, - 0x6800, + 0x0000, + 0x0000, + 0x0000, + 0xa800, 0x6800, 0x3000, 0x0000, @@ -333,9 +333,10 @@ const uint16_t wifi_offline[] = { 0x0000, 0x3000, 0x5000, - 0x5800, - 0x6800, - 0x4800, + 0xa800, + 0x0000, + 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, @@ -344,11 +345,9 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x2800, - 0x6000, - 0x6000, - 0x3000, 0x0000, + 0xa800, + 0x3000, 0x0000, 0x0000, 0x0000, @@ -358,6 +357,7 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, + 0xa800, 0x4000, 0x2800, 0x0000, @@ -371,7 +371,7 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, + 0xa800, 0x0000, 0x0000, 0x5000, @@ -396,7 +396,7 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, + 0xa800, 0x5000, 0x6800, 0x6800, @@ -404,13 +404,13 @@ const uint16_t wifi_offline[] = { 0x5000, 0x0000, 0xa800, - 0xb000, - 0xb000, + 0xf800, + 0xf800, 0x8800, 0x1800, 0x8800, - 0xb000, - 0xb000, + 0xf800, + 0xf800, 0xa800, 0x0000, 0x0000, @@ -420,7 +420,7 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, + 0xa800, 0x6000, 0x6800, 0x6800, @@ -428,13 +428,13 @@ const uint16_t wifi_offline[] = { 0x5800, 0x0000, 0x8800, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, 0xa000, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, 0x8800, 0x0000, 0x0000, @@ -445,19 +445,19 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x6000, + 0xa800, 0x6800, 0x6800, 0x6800, 0x6800, - 0x4000, + 0xa800, 0x0000, 0x8800, - 0xb000, - 0xb000, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, 0x8800, 0x0000, 0x0000, @@ -469,18 +469,18 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x5000, - 0x6800, - 0x6800, - 0x6800, - 0x6800, - 0x4800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, + 0xa800, 0x0000, 0x1800, 0xa000, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, 0xa000, 0x1800, 0x0000, @@ -494,18 +494,18 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x5000, - 0x6000, - 0x6000, - 0x5000, + 0xa800, + 0xa800, + 0xa800, + 0xa800, 0x0000, 0x0000, 0x8800, - 0xb000, - 0xb000, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, 0x8800, 0x0000, 0x0000, @@ -518,19 +518,19 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0xa800, + 0xa800, + 0xa800, + 0xa800, 0x0000, 0x8800, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, 0xa000, - 0xb000, - 0xb000, - 0xb000, + 0xf800, + 0xf800, + 0xf800, 0x8800, 0x0000, 0x0000, @@ -543,18 +543,18 @@ const uint16_t wifi_offline[] = { 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, + 0xa800, + 0xa800, 0x0000, 0x0000, 0xa800, - 0xb000, - 0xb000, + 0xf800, + 0xf800, 0x8800, 0x1800, 0x8800, - 0xb000, - 0xb000, + 0xf800, + 0xf800, 0xa800, 0x0000, 0x0000, diff --git a/firmware/keira/src/apps/icons/wifi_offline.png b/firmware/keira/src/apps/icons/wifi_offline.png index c11c0dac7fefbe321573ce0758e366693741ba93..d5b08aa7df03a4a1148e501e05a74ec10945280e 100644 GIT binary patch literal 4667 zcmeHKdsGuw8c#q0vm)Zsf=FvNVg>9Zlg#8bCCDQbf<}2n1?BWO$xL8MUL=zTsZU(7 z9u{)vW z-wztKzJINHFlIhM?3W2D5VXNQO{2}^ON3%rh{%9HEI~0C!Nd~2Sc<_4OezKIbKf71 zh+&$yd3_&SQ4jg*Pxa6CI!{8^QLDlww$=H86dB~f?yZJVmG=G1aU zQ(Rbea?Nu~obb^HA=}aDSYc&pQA5LD&g@@X{(6Wq4=a zQ|GG6H9|l{ zWX-OCX~ox_*)J2f5oHJK5B~7E-2BohBfxJDW=~_ zEDSG{ztGuxt@!$^#O|q|e0}Vx_jm6;i9XSMRiAdUQD!Ut?&{krpFJ?5L_*}a_VBgU zI=>s2x~h05yCL|Kj)%35%FBWLv=d*na01t#RBt={&59eU#&7?=st9}1%QaoF?{;OB zo(DPTp>(-)u67<~u$qN9VbzmDkJ-i?7$<&?$A%kV@pi(9WvgEupa4%QK_N}sFp5(pq5M~Q{TJ&?sQgQ4i>P?HXWowCuC)xu{ualO?^s{{ft&mWA>Y}0Co=q-)` z6@VTh4{j5Qg|NtM7LD|9(5Ws!G7!+OdN_0?Hd2&LI;>8+flPIg7J9}=3c@htZ*$sB z>~;u)h%}LA0Cj*>#iN#FZrqRuBS8UWwy|D7>`_RXG7gJ1DmG?@-Ok8Bfcp^dDD>do zSuj9pwV2v!a5CX()G7h9K1Ns#6oIirQce(v0#-l>sYD?ZmmrW*saHUxlu#NF)Tq~^ z$OtNp#X;j11IbVUav=qH3^<~YNhKsCm!o0`mC0m~LM%fe1px|-82lhIbOgl$I|Z^5 zH;s&np&|g41V{9!1eZa2k^s@5VgkYu2@Xk>22^1naYSxZuvCNrd(~<;^C*kcGd!WA%w!IYGir+EVi2%GiAW`KxdN3A zgBFo?2gpQ*ldYZX409|P*bERBXYv#fuy(K)EX7XZwAHS&T1_g!P}Lop)`IIq;54qr zX%dhQ)nVOW9i9zKFt|T_hE8iGC}YY0LNk|#9}n>0$kQnYSigid_1~x*vbg`L|ItLT zSBcMOF9n7h`nTY~T_nNA3Ap;F428I*fCSZJAYBLT)UTuh42xlf7*RmD!YGGOC9H=O zQX>MPMma2jalKKZl#OP0SdFwBx06W)Ku4ezNKf`J6hDSNsMyhHcOl7~0uT&>5lAfg zrC_3g4U3qXF}UM+(SKefoB4bW!L{rF5d9#6lnqf1-Ze?(rbsS5%8iFpr4zj=JYY& z_fPzFGq6msrRO=o+u1iv<0i*cd4MsH)@V}$yZk2x2gy?=WPo|@HH|t+mwxWZ)dN;t zQdmIu&BJ>p#IE7}WAY+_T(&$M)9eElR{u|8q}A%kvq1S!c`4&j(k~Y2#xe^G)9REqh~B zo{0s;VZV<^d*z?KU9GPqv;}`0z`4r_J5)Rc!98Kk|Cnov{@BIgwIl}S^yOaBe$ZOH z`f+H(>#m-_gjWB0-_ov-w#k*Zf+i7_Tf3SYWbPo^KS2>>+tpt(+|FG;qB&0n|7%DxpA918=k!M^{GAF z5c9GF5tkJ88!q)s-Drz521o6Ka+6AS+Fj{c1+mAZ>%Ka>Z1uLXJFzjHF`_GXj+7nw zaetvX|17cGs;;=_i@(w4dQc;~*M`1!x2f(J_owKhKU`glg`Zsb!ac+I^6K6r(-LQH zZuSZ~+#4+7$oAx2OQ)+Zf2yl(dQdgn^JbOQ{UUyp8n>kZ`?o6S)4lJ_sh}SovL5{G z^nuW)*~a`27Vq*I-niSlqUBWWg`d~$e(A*C(Dp3d&C7Wgx9aQKuhfLL@AK~baGy8u g%hrFKl2BA9{>OV delta 922 zcmV;L17-ZXB;5y)BYy#eX+uL$Nkc;*aB^>EX>4Tx04R}tkv&MmKpe$iQ>8^J4pxxj zkfA!Yi;6hbDionYs1;guFuC*#nzSS-E{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JW zDYS_3;J6>}?mh0_0Ya-dRXaURyH)^Y2v7=>69O5XqnhrmRMve!M{9TDv9?cXz<{(bT*i~}b)+;8JFrf~|R7(p%e_Rzt1Y-1gNTYc;lc?=r39ESe~TX>0fKY}x8Vq!>1 zHt`f6%LENv!?En=pZFX<@8VmmA4ff$I*Fs%xgU5Ew<%`nHbdit9c(f=+^>{WPjqz=k91mhl*x2uTFczBM4kHQm zED@Hg5^VQatA~uOXoO|#;(o-W62U`!h=S_G_oGOJ#mw_WekgetService(); + lilka::Canvas iconCanvas(240, 24); while (1) { canvas->fillScreen(lilka::display.color565(0, 0, 0)); - int16_t xOffset = 144; - // Print counter for debug purpose // TODO: Replace with actual time from NTP canvas->setTextColor(lilka::display.color565(255, 255, 255), lilka::display.color565(0, 0, 0)); canvas->setFont(FONT_9x15); - canvas->setCursor(32, 17); + canvas->setCursor(24, 17); canvas->print("Час: " + String(counter++)); - // Draw WiFi signal strength - if (networkService != NULL) { - if (networkService->getNetworkState() == NETWORK_STATE_OFFLINE) { - canvas->draw16bitRGBBitmapWithTranColor(144, 0, wifi_offline, 0, 24, 24); - } else if (networkService->getNetworkState() == NETWORK_STATE_CONNECTING) { - canvas->draw16bitRGBBitmapWithTranColor(144, 0, wifi_connecting, 0, 24, 24); - } else if (networkService->getNetworkState() == NETWORK_STATE_ONLINE) { - canvas->draw16bitRGBBitmapWithTranColor(144, 0, icons[networkService->getSignalStrength()], 0, 24, 24); - } - } - xOffset += 8 + 24; - - // Draw battery - int level = lilka::battery.readLevel(); - if (level == -1) { - canvas->draw16bitRGBBitmapWithTranColor( - xOffset, 0, battery_absent, lilka::display.color565(255, 0, 255), 32, 24 - ); - } else { - int16_t x1 = 6, y1 = 8; - int16_t fullWidth = 22, h = 8; - int filledWidth = fullWidth * level / 100; - if (filledWidth < 1) filledWidth = 1; - int16_t color = - level > 50 ? lilka::display.color565(0, 255, 0) - : (level > 20 ? lilka::display.color565(255, 255, 0) : lilka::display.color565(255, 0, 0)); - canvas->draw16bitRGBBitmapWithTranColor( - xOffset, 0, level > 10 ? battery : battery_danger, lilka::display.color565(255, 0, 255), 32, 24 - ); - canvas->fillRect(xOffset + x1 + (fullWidth - filledWidth), y1, filledWidth, h, color); - } - xOffset += 8 + 32; - canvas->setCursor(xOffset, 17); - canvas->print(String(level) + "%"); + // Draw icons + int16_t xOffset = drawIcons(&iconCanvas); + canvas->draw16bitRGBBitmap(canvas->width() - xOffset - 16, 0, iconCanvas.getFramebuffer(), 240, 24); // Draw everything queueDraw(); vTaskDelay(1000 / portTICK_PERIOD_MS); } } + +int16_t StatusBarApp::drawIcons(lilka::Canvas* iconCanvas) { + NetworkService* networkService = ServiceManager::getInstance()->getService(); + + int16_t xOffset = 0; + + iconCanvas->fillScreen(lilka::display.color565(0, 0, 0)); + iconCanvas->setFont(FONT_9x15); + + // Draw RAM usage + uint32_t freeRAM = ESP.getFreeHeap(); + uint32_t totalRAM = ESP.getHeapSize(); + int16_t padding = 1; + int16_t barWidth = 24 - padding * 2; + int16_t barHeight = barWidth; + int16_t barWidthUsed = barWidth * (totalRAM - freeRAM) / totalRAM; + iconCanvas->fillRect(xOffset + padding, padding, barWidthUsed, barHeight, lilka::display.color565(255, 0, 0)); + iconCanvas->draw16bitRGBBitmapWithTranColor(xOffset, 0, ram, lilka::display.color565(0, 0, 0), 24, 24); + xOffset += 4 + 24; + + // Draw WiFi signal strength + if (networkService != NULL) { + if (networkService->getNetworkState() == NETWORK_STATE_OFFLINE) { + iconCanvas->draw16bitRGBBitmapWithTranColor(xOffset, 0, wifi_offline, 0, 24, 24); + } else if (networkService->getNetworkState() == NETWORK_STATE_CONNECTING) { + iconCanvas->draw16bitRGBBitmapWithTranColor(xOffset, 0, wifi_connecting, 0, 24, 24); + } else if (networkService->getNetworkState() == NETWORK_STATE_ONLINE) { + iconCanvas->draw16bitRGBBitmapWithTranColor( + xOffset, 0, icons[networkService->getSignalStrength()], 0, 24, 24 + ); + } + xOffset += 4 + 24; + } + + // Draw battery + int level = lilka::battery.readLevel(); + if (level == -1) { + iconCanvas->draw16bitRGBBitmapWithTranColor( + xOffset, 0, battery_absent, lilka::display.color565(255, 0, 255), 16, 24 + ); + xOffset += 4 + 16; + } else { + int16_t x1 = 4, y1 = 6; + int16_t width = 8, fullHeight = 14; + int filledHeight = fullHeight * level / 100; + if (filledHeight < 1) filledHeight = 1; + int emptyHeight = fullHeight - filledHeight; + int16_t color = level > 50 + ? lilka::display.color565(0, 255, 0) + : (level > 20 ? lilka::display.color565(255, 255, 0) : lilka::display.color565(255, 0, 0)); + iconCanvas->draw16bitRGBBitmapWithTranColor( + xOffset, 0, level > 10 ? battery : battery_danger, lilka::display.color565(255, 0, 255), 16, 24 + ); + iconCanvas->fillRect(xOffset + x1, y1 + emptyHeight, width, filledHeight, color); + xOffset += 4 + 16; + iconCanvas->setCursor(xOffset, 17); + iconCanvas->print(String(level) + "%"); + xOffset += 36; + } + + return xOffset; +} diff --git a/firmware/keira/src/apps/statusbar.h b/firmware/keira/src/apps/statusbar.h index 42c54681..40ae2029 100644 --- a/firmware/keira/src/apps/statusbar.h +++ b/firmware/keira/src/apps/statusbar.h @@ -8,4 +8,5 @@ class StatusBarApp : public App { private: void run() override; + int16_t drawIcons(lilka::Canvas* canvas); }; diff --git a/firmware/keira/assets/keira_splash.png b/firmware/keira/src/keira_splash.png similarity index 100% rename from firmware/keira/assets/keira_splash.png rename to firmware/keira/src/keira_splash.png diff --git a/sdk/lib/lilka/assets/default_splash.png b/sdk/lib/lilka/src/lilka/default_splash.png similarity index 100% rename from sdk/lib/lilka/assets/default_splash.png rename to sdk/lib/lilka/src/lilka/default_splash.png diff --git a/sdk/lib/lilka/src/lilka/display.cpp b/sdk/lib/lilka/src/lilka/display.cpp index b4c2dd8d..bd05c812 100644 --- a/sdk/lib/lilka/src/lilka/display.cpp +++ b/sdk/lib/lilka/src/lilka/display.cpp @@ -105,15 +105,19 @@ void Display::drawImageTransformed(Image* image, int16_t destX, int16_t destY, T // Transform image around its pivot. // Draw the rotated image at the specified position. + int32_t imageWidth = image->width; + int32_t imageHeight = image->height; + // Calculate the coordinates of the four corners of the destination rectangle. - IntVector v1 = transform.apply(IntVector(-image->pivotX, -image->pivotY)); - IntVector v2 = transform.apply(IntVector(image->width - image->pivotX, -image->pivotY)); - IntVector v3 = transform.apply(IntVector(-image->pivotX, image->height - image->pivotY)); - IntVector v4 = transform.apply(IntVector(image->width - image->pivotX, image->height - image->pivotY)); + int_vector_t v1 = transform.apply(int_vector_t{-image->pivotX, -image->pivotY}); + int_vector_t v2 = transform.apply(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + int_vector_t v3 = transform.apply(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + int_vector_t v4 = transform.apply(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); // Find the bounding box of the transformed image. - IntVector topLeft = IntVector(min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))); - IntVector bottomRight = IntVector(max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))); + int_vector_t topLeft = int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; + int_vector_t bottomRight = + int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; // Create a new image to hold the transformed image. Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); @@ -122,7 +126,7 @@ void Display::drawImageTransformed(Image* image, int16_t destX, int16_t destY, T Transform inverse = transform.inverse(); for (int y = topLeft.y; y < bottomRight.y; y++) { for (int x = topLeft.x; x < bottomRight.x; x++) { - IntVector v = inverse.apply(IntVector(x, y)); + int_vector_t v = inverse.apply(int_vector_t{x, y}); // Apply pivot offset v.x += image->pivotX; v.y += image->pivotY; @@ -184,34 +188,44 @@ void Canvas::drawImageTransformed(Image* image, int16_t destX, int16_t destY, Tr // Draw the rotated image at the specified position. // Calculate the coordinates of the four corners of the destination rectangle. - IntVector v1 = transform.apply(IntVector(-image->pivotX, -image->pivotY)); - IntVector v2 = transform.apply(IntVector(image->width - image->pivotX, -image->pivotY)); - IntVector v3 = transform.apply(IntVector(-image->pivotX, image->height - image->pivotY)); - IntVector v4 = transform.apply(IntVector(image->width - image->pivotX, image->height - image->pivotY)); + int32_t imageWidth = image->width; + int32_t imageHeight = image->height; + + // Calculate the coordinates of the four corners of the destination rectangle. + int_vector_t v1 = transform.apply(int_vector_t{-image->pivotX, -image->pivotY}); + int_vector_t v2 = transform.apply(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + int_vector_t v3 = transform.apply(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + int_vector_t v4 = transform.apply(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); // Find the bounding box of the transformed image. - IntVector topLeft = IntVector(min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))); - IntVector bottomRight = IntVector(max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))); + int_vector_t topLeft = int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; + int_vector_t bottomRight = + int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; // Create a new image to hold the transformed image. Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); // Draw the transformed image to the new image. Transform inverse = transform.inverse(); - for (int y = topLeft.y; y < bottomRight.y; y++) { - for (int x = topLeft.x; x < bottomRight.x; x++) { - IntVector v = inverse.apply(IntVector(x, y)); + uint64_t start = esp_timer_get_time(); + int_vector_t point{0, 0}; + for (point.y = topLeft.y; point.y < bottomRight.y; point.y++) { + for (point.x = topLeft.x; point.x < bottomRight.x; point.x++) { + int_vector_t v = inverse.apply(point); // Apply pivot offset v.x += image->pivotX; v.y += image->pivotY; if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { - destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = + destImage.pixels[point.x - topLeft.x + (point.y - topLeft.y) * destImage.width] = image->pixels[v.x + v.y * image->width]; } else { - destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; + destImage.pixels[point.x - topLeft.x + (point.y - topLeft.y) * destImage.width] = + image->transparentColor; } } } + uint64_t end = esp_timer_get_time(); + Serial.println("Transformed image in " + String(end - start) + " us"); // TODO: Draw directly to the canvas? drawImage(&destImage, destX + topLeft.x, destY + topLeft.y); @@ -348,12 +362,12 @@ Transform Transform::inverse() { return t; } -IntVector Transform::apply(IntVector v) { +inline int_vector_t Transform::apply(int_vector_t v) { // Apply this transform to a vector - return IntVector(matrix[0][0] * v.x + matrix[0][1] * v.y, matrix[1][0] * v.x + matrix[1][1] * v.y); -} - -IntVector::IntVector(int32_t x, int32_t y) : x(x), y(y) { + return int_vector_t{ + static_cast(matrix[0][0] * v.x + matrix[0][1] * v.y), + static_cast(matrix[1][0] * v.x + matrix[1][1] * v.y) + }; } Display display; diff --git a/sdk/lib/lilka/src/lilka/display.h b/sdk/lib/lilka/src/lilka/display.h index 823543ae..aec1ace3 100644 --- a/sdk/lib/lilka/src/lilka/display.h +++ b/sdk/lib/lilka/src/lilka/display.h @@ -22,7 +22,10 @@ namespace lilka { class Canvas; class Image; class Transform; -class IntVector; +typedef struct int_vector_t { + int32_t x; + int32_t y; +} int_vector_t; /// Клас для роботи з дисплеєм. /// @@ -387,19 +390,12 @@ class Transform { /// @note Інвертне перетворення - це таке перетворення, яке скасує це перетворення, тобто є зворотнім до цього. Transform inverse(); - IntVector apply(IntVector vector); + int_vector_t apply(int_vector_t vector); // Матриця перетворення float matrix[2][2]; // [рядок][стовпець] }; -class IntVector { -public: - IntVector(int32_t x, int32_t y); - int32_t x; - int32_t y; -}; - /// Екземпляр класу `Display`, який можна використовувати для роботи з дисплеєм. /// Вам не потрібно інстанціювати `Display` вручну. extern Display display; diff --git a/sdk/lib/lilka/src/lilka/ui.cpp b/sdk/lib/lilka/src/lilka/ui.cpp index 8ce0866c..68f0ad29 100644 --- a/sdk/lib/lilka/src/lilka/ui.cpp +++ b/sdk/lib/lilka/src/lilka/ui.cpp @@ -255,4 +255,193 @@ void ProgressDialog::draw(Arduino_GFX* canvas) { canvas->print(buf); } +#define K_L0 1 +#define K_L1 2 +#define K_L2 3 +#define K_BS 8 + +// 2 layers, 4 rows, 12 columns +const uint8_t keyboard[LILKA_KB_LAYERS][LILKA_KB_ROWS * LILKA_KB_COLS] = { + // Layer 0 + { + ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ' ', // R1 + ' ', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', ' ', // R2 + K_L1, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', K_BS, ' ', // R3 + K_L2, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', ' ', ' ', // R4 + }, + // Layer 1 (shifted layer 0) + { + ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', ' ', // R1 + ' ', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', ' ', // R2 + K_L0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', K_BS, ' ', // R3 + K_L2, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', ' ', ' ', // R4 + }, + // Layer 2 (special keys - braces, slashes, etc) + { + ' ', '{', '}', '[', ']', '|', '\\', ':', ';', '\'', '"', ' ', // R1 + ' ', '<', '>', '?', '/', '!', '@', '#', '$', '%', '^', ' ', // R2 + ' ', '(', ')', '-', '_', '=', '+', ':', ';', '\'', K_BS, ' ', // R3 + K_L0, '<', '>', '?', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // R4 + }, +}; + +InputDialog::InputDialog(String title) { + this->title = title; + this->masked = false; + + this->done = false; + this->value = ""; + + this->layer = 0; + this->cx = 0; + this->cy = 0; + + this->lastBlink = 0; + this->blinkPhase = true; +} + +void InputDialog::setMasked(bool masked) { + this->masked = masked; +} + +void InputDialog::update() { + if (millis() - lastBlink > 300) { + lastBlink = millis(); + blinkPhase = !blinkPhase; + } + + State state = controller.getState(); + if (state.a.justPressed) { + // TODO: Handle key press + const uint8_t* layerKeys = keyboard[layer]; + uint8_t key = layerKeys[cy * LILKA_KB_COLS + cx]; + if (key == K_L0) { + layer = 0; + } else if (key == K_L1) { + layer = 1; + } else if (key == K_L2) { + layer = 2; + } else if (key == K_BS) { + if (value.length() > 0) { + value.remove(value.length() - 1); + } + } else if (key) { + value += (char)key; + } + resetBlink(); + } else if (state.b.justPressed) { + if (value.length() > 0) { + value.remove(value.length() - 1); + } + resetBlink(); + } else if (state.start.justPressed) { + done = true; + } else if (state.up.justPressed) { + cy--; + if (cy < 0) { + cy = LILKA_KB_ROWS - 1; + } + } else if (state.down.justPressed) { + cy++; + if (cy > LILKA_KB_ROWS - 1) { + cy = 0; + } + } else if (state.left.justPressed) { + cx--; + if (cx < 0) { + cx = LILKA_KB_COLS - 1; + } + } else if (state.right.justPressed) { + cx++; + if (cx > LILKA_KB_COLS - 1) { + cx = 0; + } + } +} + +void InputDialog::draw(Arduino_GFX* canvas) { + // Draw keyboard + int16_t kbTop = canvas->height() / 2 - 32; + int16_t kbHeight = canvas->height() / 2; + int16_t kbWidth = canvas->width(); + + canvas->fillRect(0, 0, canvas->width(), canvas->height(), canvas->color565(0, 0, 0)); + canvas->setTextColor(canvas->color565(255, 255, 255)); + canvas->setFont(FONT_10x20); + + canvas->setTextBound(4, 4, canvas->width() - 8, canvas->height() - 8); + canvas->setCursor(4, 20); + canvas->println(title); + + canvas->setTextBound(16, 16, canvas->width() - 32, canvas->height() - 32); + canvas->setCursor(16, 48); + if (masked) { + for (int i = 0; i < value.length(); i++) { + canvas->print("*"); + } + } else { + canvas->print(value); + } + if (blinkPhase) { + canvas->print("|"); + } + + // canvas->setTextBound(0, kbTop + kbHeight, canvas->width(), canvas->height()); + + const uint8_t* layerKeys = keyboard[layer]; + + for (int i = 0; i < LILKA_KB_ROWS; i++) { + for (int j = 0; j < LILKA_KB_COLS; j++) { + // Draw rect if key is focused + if (i == cy && j == cx) { + canvas->fillRect( + j * kbWidth / LILKA_KB_COLS, + kbTop + i * kbHeight / LILKA_KB_ROWS, + kbWidth / LILKA_KB_COLS, + kbHeight / LILKA_KB_ROWS, + canvas->color565(255, 64, 0) + ); + } + uint8_t key = layerKeys[i * LILKA_KB_COLS + j]; + if (key) { + String caption; + if (key == K_L0 || key == K_L1 || key == K_L2) { + caption = key == K_L0 ? "ab" : key == K_L1 ? "AB" : "!@"; + } else if (key == K_BS) { + caption = "<-"; + } else { + caption = (char)key; + } + int16_t x1, y1; + uint16_t w, h; + // Calculate text top-left corner and size + canvas->getTextBounds(caption, 0, 0, &x1, &y1, &w, &h); + // Print centered text + canvas->setCursor( + j * kbWidth / LILKA_KB_COLS + (kbWidth / LILKA_KB_COLS - w) / 2, + kbTop + i * kbHeight / LILKA_KB_ROWS + (kbHeight / LILKA_KB_ROWS - h) / 2 - y1 + ); + canvas->print(caption); + } + } + } +} + +bool InputDialog::isDone() { + if (done) { + done = false; + return true; + } + return false; +} + +String InputDialog::getValue() { + return value; +} + +void InputDialog::resetBlink() { + lastBlink = millis(); + blinkPhase = true; +} + } // namespace lilka diff --git a/sdk/lib/lilka/src/lilka/ui.h b/sdk/lib/lilka/src/lilka/ui.h index f2d43ca1..80a00cc5 100644 --- a/sdk/lib/lilka/src/lilka/ui.h +++ b/sdk/lib/lilka/src/lilka/ui.h @@ -201,6 +201,37 @@ class ProgressDialog { int16_t progress; }; +#define LILKA_KB_LAYERS 3 +#define LILKA_KB_ROWS 4 +#define LILKA_KB_COLS 12 + +/// Клас для відображення діалогового вікна введення. +/// +/// Малює вікно введення та екранну клавіатуру, дозволяє вводити текст та підтверджувати введення. +class InputDialog { +public: + explicit InputDialog(String title); + void setMasked(bool masked); + void update(); + void draw(Arduino_GFX* canvas); + bool isDone(); + String getValue(); + +private: + void resetBlink(); + + String title; + bool masked; + String value; + bool done; + + int16_t layer; + int16_t cx; + int16_t cy; + int64_t lastBlink; + bool blinkPhase; +}; + } // namespace lilka #endif // LILKA_UI_H diff --git a/sdk/tools/image2code/ship.h b/sdk/tools/image2code/ship.h new file mode 100644 index 00000000..248e5869 --- /dev/null +++ b/sdk/tools/image2code/ship.h @@ -0,0 +1,1032 @@ +// This is a generated file, do not edit. +// clang-format off +#include +const uint16_t ship_width = 32; +const uint16_t ship_height = 32; +const uint16_t ship[] = { + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xe800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xe800, + 0xe800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xe800, + 0xe800, + 0xe800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xe800, + 0xe800, + 0xe800, + 0xe800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xe800, + 0xe800, + 0xe800, + 0xe800, + 0xe800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0x0000, + 0x0000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0xaaa0, + 0x0000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x57ff, + 0x57ff, + 0x57ff, + 0x52bf, + 0x52bf, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0xf800, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x57ff, + 0x57ff, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xf800, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x57ff, + 0x57ff, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x57ff, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x57ff, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffea, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x5000, + 0x5000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0x0000, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x52bf, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0xaaa0, + 0x0000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0xffea, + 0x0000, + 0xaaa0, + 0x0000, + 0x0000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffea, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x5000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x8000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x8000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x8000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0x0000, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, +}; +// clang-format on From 3e572d77816ba958f5796f86eaf7a891ab18e6b9 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 21:55:27 +0200 Subject: [PATCH 7/8] lib: update docs on display transforms & pivots --- sdk/lib/lilka/src/lilka/display.h | 47 +++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/sdk/lib/lilka/src/lilka/display.h b/sdk/lib/lilka/src/lilka/display.h index aec1ace3..ccc50602 100644 --- a/sdk/lib/lilka/src/lilka/display.h +++ b/sdk/lib/lilka/src/lilka/display.h @@ -176,8 +176,8 @@ class Display : public Arduino_ST7789 { /// Намалювати зображення. /// @param image Вказівник на зображення (об'єкт класу `lilka::Image`). - /// @param x Координата X лівого верхнього кута зображення. - /// @param y Координата Y лівого верхнього кута зображення. + /// @param x Координата X осі зображення. + /// @param y Координата Y осі зображення. /// /// Приклад використання: /// @@ -194,8 +194,8 @@ class Display : public Arduino_ST7789 { void drawImage(Image* image, int16_t x, int16_t y); /// Намалювати зображення з афінними перетвореннями. /// @param image Вказівник на зображення (об'єкт класу `lilka::Image`). - /// @param x Координата X лівого верхнього кута зображення. - /// @param y Координата Y лівого верхнього кута зображення. + /// @param x Координата X осі зображення. + /// @param y Координата Y осі зображення. /// @param transform Об'єкт класу `lilka::Transform`, який містить матрицю перетворення. /// @note Зверніть увагу, що перетворення - це повільніше, ніж звичайне малювання зображення, оскільки обчислює координати пікселів "на льоту". Використовуйте його лише тоді, коли не можете заздалегідь створити обернені копії зображеня за допомогою методів `lilka::Image::rotate`, `lilka::Image::flipX` та `lilka::Image::flipY`. /// @see lilka::Transform @@ -251,14 +251,15 @@ class Display : public Arduino_ST7789 { /// Клас для роботи з графічним буфером. /// -/// При частому перемальовуванні екрану без використання буфера, може спостерігатися мерехтіння. +/// При частому перемальовуванні екрану без використання буфера може спостерігатися мерехтіння. /// Наприклад, якщо використовувати метод `fillScreen` для очищення екрану перед кожним викликом `print`, /// то текст буде мерехтіти. /// /// Щоб уникнути цього, можна використовувати буфер. Цей клас дозволяє малювати графічні об'єкти на буфері, /// а потім відобразити його на екрані за допомогою методу `lilka::display.renderCanvas`. /// -/// Такий підхід дозволяє зменшити мерехтіння, але збільшує використання пам'яті. Він називається "буферизація". +/// Такий підхід дозволяє зменшити мерехтіння, але збільшує використання пам'яті. Він називається "буферизація", +/// оскільки ми спершу малюємо на буфері, а тоді відображаємо буфер на екрані. /// /// Цей клас, як і `Display`, є підкласом `Arduino_GFX` з бібліотеки `Arduino_GFX_Library`. /// Це означає, що майже всі методи, які доступні в `Display`, також доступні в `Canvas`. @@ -273,11 +274,11 @@ class Display : public Arduino_ST7789 { /// } /// /// void loop() { -/// lilka::Canvas canvas; +/// lilka::Canvas canvas; // Створити новий Canvas зі стандартним розміром (розмір дисплею) /// int y = 100; /// while (1) { /// canvas.fillScreen(lilka::display.color565(0, 0, 0)); // Заповнити буфер чорним кольором -/// canvas.setCursor(32, 0); +/// canvas.setCursor(32, y); /// canvas.setTextColor(lilka::display.color565(0, 0, 0)); // Білий текст /// canvas.print("Привіт, Лілка!"); /// lilka::display.renderCanvas(&canvas); // Відобразити буфер на екрані - жодного мерехтіння! @@ -312,6 +313,8 @@ class Canvas : public Arduino_Canvas { /// Містить розміри, прозорий колір та пікселі зображення (в 16-бітному форматі, 5-6-5). /// Пікселі зберігаються в рядку зліва направо, зверху вниз. /// +/// Вісь зображення - це точка, яка вказує на центр зображення. Це дозволяє вам встановити точку, відносно якої буде відображатися зображення, а також навколо якої буде відбуватися перетворення зображення. +/// /// @note Основна відмінність Image від поняття "bitmap" погялає в тому, що Image містить масив пікселів, розміри зображення і прозорий колір, в той час як "bitmap" - це просто масив пікселів. class Image { public: @@ -319,6 +322,10 @@ class Image { ~Image(); /// Обернути зображення на заданий кут (в градусах) і записати результат в `dest`. /// + /// Цей метод, а також методи `flipX` та `flipY`, зручно використовувати для створення обернених та віддзеркалених копій зображення, якщо ви заздалегідь знаєте, які варіанти зображення вам знадобляться. + /// + /// Замість них можна використовувати клас `lilka::Transform` та його методи, які дозволяють виконувати та комбінувати складніші перетворення "на льоту", але такі перетворення є повільнішими. + /// /// @param angle Кут обертання в градусах. /// @param dest Вказівник на Image, в яке буде записано обернуте зображення. /// @param blankColor 16-бітний колір (5-6-5), який буде використаний для заповнення пікселів, які виходять за межі зображення. @@ -339,6 +346,7 @@ class Image { /// delete image; /// delete rotatedImage; /// @endcode + /// @see Display::drawImageTransformed, Canvas::drawImageTransformed, Transform void rotate(int16_t angle, Image* dest, int32_t blankColor); /// Віддзеркалити зображення по горизонталі і записати результат в `dest`. void flipX(Image* dest); @@ -358,7 +366,9 @@ class Image { /// Афінні перетворення - це перетворення, які зберігають паралельність ліній. /// Вони включають в себе обертання, масштабування та віддзеркалення. /// -/// Наприклад, ось цей код обертає зображення на 30 градусів та віддзеркалює його по горизонталі: +/// Перетворення - це всього лиш матриця 2x2. Застосування перетворення до вектора - це множення цього вектора на матрицю перетворення. Магія! +/// +/// Наприклад, ось цей код обертає зображення на 30 градусів і тоді віддзеркалює його по горизонталі: /// /// @code /// lilka::Transform transform = lilka::Transform().rotate(30).flipX(); @@ -374,23 +384,38 @@ class Transform { /// /// Оскільки на екрані вісь Y вказує вниз, обертання буде здійснено за годинниковою стрілкою. /// @param angle Кут обертання в градусах. + /// @return Нове перетворення. Transform rotate(int16_t angle); /// Масштабувати по X та Y. /// /// Щоб віддзеркалити зображення, використайте від'ємні значення (наприклад, -1). /// @param scaleX Масштаб по X. /// @param scaleY Масштаб по Y. + /// @return Нове перетворення. Transform scale(float scaleX, float scaleY); - /// Застосувати інше перетворення до цього. + /// Помножити це перетворення на інше. + /// + /// @note Зверніть увагу: при комбінації перетворень порядок важливий, і він є оберненим до порядку множення матриць! В результаті цього, перетворення other буде виконано **перед** поточним перетворенням. Тобто якщо в вас є деякі перетворення `A` та `B`, то перетворення `A.multiply(B)` утворить нове перетворення, в якому спочатку виконається перетворення `B`, а потім `A`. + /// @note Для уникнення плутанини рекомендуємо використовувати більш високорівневі методи, такі як `rotate` та `scale`. /// @param other Інше перетворення. + /// @return Перетворення, яке є результатом застосування цього перетворення після `other` перетворення. + /// @code + /// lilka::Transform rotate30 = lilka::Transform().rotate(30); // обернути на 30 градусів + /// lilka::Transform scale2x = lilka::Transform().scale(2, 2); // збільшити в 2 рази + /// lilka::Transform scaleThenRotate = rotate30.multiply(scale2x); // результат - це перетворення "спочатку збільшити, а потім обернути", а не навпаки! + /// @endcode Transform multiply(Transform other); /// Інвертувати перетворення. /// @note Інвертне перетворення - це таке перетворення, яке скасує це перетворення, тобто є зворотнім до цього. + /// @return Інвертоване перетворення. Transform inverse(); - int_vector_t apply(int_vector_t vector); + /// Перетворити вектор, використовуючи це перетворення. + /// @param vector Вхідний вектор. + /// @return Результат перетворення. + int_vector_t transform(int_vector_t vector); // Матриця перетворення float matrix[2][2]; // [рядок][стовпець] From 6273723b2090ea9c8c15ec3fe9bbd47ca837de79 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 12 Mar 2024 22:42:35 +0200 Subject: [PATCH 8/8] lib: fix typo in transform method --- sdk/lib/lilka/src/lilka/display.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk/lib/lilka/src/lilka/display.cpp b/sdk/lib/lilka/src/lilka/display.cpp index bd05c812..97c72705 100644 --- a/sdk/lib/lilka/src/lilka/display.cpp +++ b/sdk/lib/lilka/src/lilka/display.cpp @@ -109,10 +109,10 @@ void Display::drawImageTransformed(Image* image, int16_t destX, int16_t destY, T int32_t imageHeight = image->height; // Calculate the coordinates of the four corners of the destination rectangle. - int_vector_t v1 = transform.apply(int_vector_t{-image->pivotX, -image->pivotY}); - int_vector_t v2 = transform.apply(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); - int_vector_t v3 = transform.apply(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); - int_vector_t v4 = transform.apply(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); + int_vector_t v1 = transform.transform(int_vector_t{-image->pivotX, -image->pivotY}); + int_vector_t v2 = transform.transform(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + int_vector_t v3 = transform.transform(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + int_vector_t v4 = transform.transform(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); // Find the bounding box of the transformed image. int_vector_t topLeft = int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; @@ -126,7 +126,7 @@ void Display::drawImageTransformed(Image* image, int16_t destX, int16_t destY, T Transform inverse = transform.inverse(); for (int y = topLeft.y; y < bottomRight.y; y++) { for (int x = topLeft.x; x < bottomRight.x; x++) { - int_vector_t v = inverse.apply(int_vector_t{x, y}); + int_vector_t v = inverse.transform(int_vector_t{x, y}); // Apply pivot offset v.x += image->pivotX; v.y += image->pivotY; @@ -192,10 +192,10 @@ void Canvas::drawImageTransformed(Image* image, int16_t destX, int16_t destY, Tr int32_t imageHeight = image->height; // Calculate the coordinates of the four corners of the destination rectangle. - int_vector_t v1 = transform.apply(int_vector_t{-image->pivotX, -image->pivotY}); - int_vector_t v2 = transform.apply(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); - int_vector_t v3 = transform.apply(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); - int_vector_t v4 = transform.apply(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); + int_vector_t v1 = transform.transform(int_vector_t{-image->pivotX, -image->pivotY}); + int_vector_t v2 = transform.transform(int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + int_vector_t v3 = transform.transform(int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + int_vector_t v4 = transform.transform(int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); // Find the bounding box of the transformed image. int_vector_t topLeft = int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; @@ -211,7 +211,7 @@ void Canvas::drawImageTransformed(Image* image, int16_t destX, int16_t destY, Tr int_vector_t point{0, 0}; for (point.y = topLeft.y; point.y < bottomRight.y; point.y++) { for (point.x = topLeft.x; point.x < bottomRight.x; point.x++) { - int_vector_t v = inverse.apply(point); + int_vector_t v = inverse.transform(point); // Apply pivot offset v.x += image->pivotX; v.y += image->pivotY; @@ -362,7 +362,7 @@ Transform Transform::inverse() { return t; } -inline int_vector_t Transform::apply(int_vector_t v) { +inline int_vector_t Transform::transform(int_vector_t v) { // Apply this transform to a vector return int_vector_t{ static_cast(matrix[0][0] * v.x + matrix[0][1] * v.y),