aboutsummaryrefslogtreecommitdiffstats
path: root/src/Components/Gfx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Components/Gfx')
-rw-r--r--src/Components/Gfx/Gfx.cpp102
-rw-r--r--src/Components/Gfx/Gfx.h18
2 files changed, 94 insertions, 26 deletions
diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp
index 94106513..2f64596c 100644
--- a/src/Components/Gfx/Gfx.cpp
+++ b/src/Components/Gfx/Gfx.cpp
@@ -7,23 +7,33 @@ Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
}
void Gfx::Init() {
- lcd.Init();
+
}
void Gfx::ClearScreen() {
SetBackgroundColor(0x0000);
+
+ state.remainingIterations = 240 + 1;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::FillRectangle;
+
lcd.BeginDrawBuffer(0, 0, width, height);
- for(int i = 0; i < height; i++) {
- lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
- }
- lcd.EndDrawBuffer();
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
}
-void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color) {
+void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
SetBackgroundColor(color);
- lcd.BeginDrawBuffer(0, 0, width, height);
- lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2, 240);
- lcd.EndDrawBuffer();
+
+ state.remainingIterations = 240 + 1;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::FillRectangle;
+
+ lcd.BeginDrawBuffer(x, y, w, h);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
}
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
@@ -64,31 +74,37 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) {
uint8_t char_idx = c - font->startChar;
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
+ uint16_t bg = 0x0000;
if (c == ' ') {
*x += font->height / 2;
return;
}
- // TODO For now, LCD and SPI driver start a new transfer (cs pin + set address windows + write byte) FOR EACH PIXEL!
- // This could be improved by setting CS pin, DC pin and address window ONLY ONCE for the whole character
-
- lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height);
- uint16_t bg = 0x0000;
- for (uint16_t i = 0; i < font->height; i++) {
- for (uint16_t j = 0; j < bytes_in_line; j++) {
- for (uint8_t k = 0; k < 8; k++) {
- if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + i * bytes_in_line + j]) {
- buffer[(j*8)+k] = color;
- }
- else {
- buffer[(j*8)+k] = bg;
- }
+ // Build first line
+ for (uint16_t j = 0; j < bytes_in_line; j++) {
+ for (uint8_t k = 0; k < 8; k++) {
+ if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
+ buffer[(j*8)+k] = color;
+ }
+ else {
+ buffer[(j*8)+k] = bg;
}
}
- lcd.NextDrawBuffer(reinterpret_cast<uint8_t *>(&buffer), bytes_in_line*8*2);
}
- lcd.EndDrawBuffer();
+
+ state.remainingIterations = font->height + 0;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::DrawChar;
+ state.font = const_cast<FONT_INFO *>(font);
+ state.character = c;
+ state.color = color;
+
+ lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
+
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
}
@@ -110,4 +126,40 @@ void Gfx::SetBackgroundColor(uint16_t color) {
}
}
+bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
+ if(!state.busy) return false;
+ state.remainingIterations--;
+ if (state.remainingIterations == 0) {
+ state.busy = false;
+ return false;
+ }
+
+ if(state.action == Action::FillRectangle) {
+ *data = reinterpret_cast<uint8_t *>(buffer);
+ size = width * 2;
+ } else if(state.action == Action::DrawChar) {
+ uint16_t bg = 0x0000;
+ uint8_t char_idx = state.character - state.font->startChar;
+ uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
+
+ for (uint16_t j = 0; j < bytes_in_line; j++) {
+ for (uint8_t k = 0; k < 8; k++) {
+ if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) {
+ buffer[(j*8)+k] = state.color;
+ }
+ else {
+ buffer[(j*8)+k] = bg;
+ }
+ }
+ }
+
+ *data = reinterpret_cast<uint8_t *>(buffer);
+ size = bytes_in_line*8*2;
+ }
+
+ state.currentIteration++;
+
+ return true;
+}
+
diff --git a/src/Components/Gfx/Gfx.h b/src/Components/Gfx/Gfx.h
index d8728701..81c5f387 100644
--- a/src/Components/Gfx/Gfx.h
+++ b/src/Components/Gfx/Gfx.h
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <nrf_font.h>
+#include <drivers/BufferProvider.h>
namespace Pinetime {
@@ -8,7 +9,7 @@ namespace Pinetime {
class St7789;
}
namespace Components {
- class Gfx {
+ class Gfx : public Pinetime::Drivers::BufferProvider {
public:
explicit Gfx(Drivers::St7789& lcd);
void Init();
@@ -19,11 +20,26 @@ namespace Pinetime {
void Sleep();
void Wakeup();
+ bool GetNextBuffer(uint8_t **buffer, size_t &size) override;
private:
static constexpr uint8_t width = 240;
static constexpr uint8_t height = 240;
+ enum class Action { None, FillRectangle, DrawChar};
+ struct State {
+ State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {}
+ volatile bool busy;
+ volatile Action action;
+ volatile uint16_t remainingIterations;
+ volatile uint16_t currentIteration;
+ volatile FONT_INFO *font;
+ volatile uint16_t color;
+ volatile uint8_t character;
+ };
+
+ volatile State state;
+
uint16_t buffer[width]; // 1 line buffer
Drivers::St7789& lcd;