Move to SDK EInkDisplay and enable anti-aliased 2-bit text (#5)
* First pass at moving to SDK EInkDisplay library * Add 2-bit grayscale text and anti-aliased rendering of text * Render status bar for empty chapters * Refresh screen every 15 pages to avoid ghosting * Simplify boot and sleep screens * Give FileSelectionScreen task more stack memory * Move text around slightly on Boot and Sleep screens * Re-use existing buffer and write to whole screen for 'partial update'
This commit is contained in:
@@ -11,4 +11,9 @@ void BootLogoScreen::onEnter() {
|
||||
renderer.clearScreen();
|
||||
// Location for images is from top right in landscape orientation
|
||||
renderer.drawImage(CrossLarge, (pageHeight - 128) / 2, (pageWidth - 128) / 2, 128, 128);
|
||||
const int width = renderer.getUiTextWidth("CrossPoint", BOLD);
|
||||
renderer.drawUiText((pageWidth - width)/ 2, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
|
||||
const int bootingWidth = renderer.getSmallTextWidth("BOOTING");
|
||||
renderer.drawSmallText((pageWidth - bootingWidth) / 2, pageHeight / 2 + 95, "BOOTING");
|
||||
renderer.flushDisplay();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "EpubReaderScreen.h"
|
||||
|
||||
#include <EpdRenderer.h>
|
||||
#include <Epub/Page.h>
|
||||
#include <SD.h>
|
||||
|
||||
#include "Battery.h"
|
||||
|
||||
constexpr int PAGES_PER_REFRESH = 20;
|
||||
constexpr int PAGES_PER_REFRESH = 15;
|
||||
constexpr unsigned long SKIP_CHAPTER_MS = 700;
|
||||
|
||||
void EpubReaderScreen::taskTrampoline(void* param) {
|
||||
@@ -128,7 +129,7 @@ void EpubReaderScreen::displayTaskLoop() {
|
||||
if (updateRequired) {
|
||||
updateRequired = false;
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
renderPage();
|
||||
renderScreen();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
@@ -136,7 +137,7 @@ void EpubReaderScreen::displayTaskLoop() {
|
||||
}
|
||||
|
||||
// TODO: Failure handling
|
||||
void EpubReaderScreen::renderPage() {
|
||||
void EpubReaderScreen::renderScreen() {
|
||||
if (!epub) {
|
||||
return;
|
||||
}
|
||||
@@ -159,10 +160,12 @@ void EpubReaderScreen::renderPage() {
|
||||
constexpr int y = 50;
|
||||
const int w = textWidth + margin * 2;
|
||||
const int h = renderer.getLineHeight() + margin * 2;
|
||||
renderer.swapBuffers();
|
||||
renderer.fillRect(x, y, w, h, 0);
|
||||
renderer.drawText(x + margin, y + margin, "Indexing...");
|
||||
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
|
||||
renderer.flushArea(x, y, w, h);
|
||||
renderer.flushDisplay(EInkDisplay::HALF_REFRESH);
|
||||
pagesUntilFullRefresh = 0;
|
||||
}
|
||||
|
||||
section->setupCacheDir();
|
||||
@@ -184,16 +187,29 @@ void EpubReaderScreen::renderPage() {
|
||||
}
|
||||
|
||||
renderer.clearScreen();
|
||||
section->renderPage();
|
||||
renderStatusBar();
|
||||
if (pagesUntilFullRefresh <= 1) {
|
||||
renderer.flushDisplay(false);
|
||||
pagesUntilFullRefresh = PAGES_PER_REFRESH;
|
||||
} else {
|
||||
|
||||
if (section->pageCount == 0) {
|
||||
Serial.println("No pages to render");
|
||||
const int width = renderer.getTextWidth("Empty chapter", BOLD);
|
||||
renderer.drawText((renderer.getPageWidth() - width) / 2, 300, "Empty chapter", true, BOLD);
|
||||
renderStatusBar();
|
||||
renderer.flushDisplay();
|
||||
pagesUntilFullRefresh--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (section->currentPage < 0 || section->currentPage >= section->pageCount) {
|
||||
Serial.printf("Page out of bounds: %d (max %d)\n", section->currentPage, section->pageCount);
|
||||
const int width = renderer.getTextWidth("Out of bounds", BOLD);
|
||||
renderer.drawText((renderer.getPageWidth() - width) / 2, 300, "Out of bounds", true, BOLD);
|
||||
renderStatusBar();
|
||||
renderer.flushDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
const Page* p = section->loadPageFromSD();
|
||||
renderContents(p);
|
||||
delete p;
|
||||
|
||||
File f = SD.open((epub->getCachePath() + "/progress.bin").c_str(), FILE_WRITE);
|
||||
uint8_t data[4];
|
||||
data[0] = currentSpineIndex & 0xFF;
|
||||
@@ -204,6 +220,36 @@ void EpubReaderScreen::renderPage() {
|
||||
f.close();
|
||||
}
|
||||
|
||||
void EpubReaderScreen::renderContents(const Page* p) {
|
||||
p->render(renderer);
|
||||
renderStatusBar();
|
||||
if (pagesUntilFullRefresh <= 1) {
|
||||
renderer.flushDisplay(EInkDisplay::HALF_REFRESH);
|
||||
pagesUntilFullRefresh = PAGES_PER_REFRESH;
|
||||
} else {
|
||||
renderer.flushDisplay();
|
||||
pagesUntilFullRefresh--;
|
||||
}
|
||||
|
||||
// grayscale rendering
|
||||
{
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setFontRendererMode(GRAYSCALE_LSB);
|
||||
p->render(renderer);
|
||||
renderer.copyGrayscaleLsbBuffers();
|
||||
|
||||
// Render and copy to MSB buffer
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setFontRendererMode(GRAYSCALE_MSB);
|
||||
p->render(renderer);
|
||||
renderer.copyGrayscaleMsbBuffers();
|
||||
|
||||
// display grayscale part
|
||||
renderer.displayGrayBuffer();
|
||||
renderer.setFontRendererMode(BW);
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderScreen::renderStatusBar() const {
|
||||
const auto pageWidth = renderer.getPageWidth();
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ class EpubReaderScreen final : public Screen {
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void renderPage();
|
||||
void renderScreen();
|
||||
void renderContents(const Page *p);
|
||||
void renderStatusBar() const;
|
||||
|
||||
public:
|
||||
|
||||
@@ -51,7 +51,7 @@ void FileSelectionScreen::onEnter() {
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&FileSelectionScreen::taskTrampoline, "FileSelectionScreenTask",
|
||||
1024, // Stack size
|
||||
2048, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&displayTaskHandle // Task handle
|
||||
@@ -120,7 +120,7 @@ void FileSelectionScreen::render() const {
|
||||
|
||||
const auto pageWidth = renderer.getPageWidth();
|
||||
const auto titleWidth = renderer.getTextWidth("CrossPoint Reader", BOLD);
|
||||
renderer.drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", 1, BOLD);
|
||||
renderer.drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", true, BOLD);
|
||||
|
||||
if (files.empty()) {
|
||||
renderer.drawUiText(10, 50, "No EPUBs found");
|
||||
@@ -130,7 +130,7 @@ void FileSelectionScreen::render() const {
|
||||
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
const auto file = files[i];
|
||||
renderer.drawUiText(10, 50 + i * 30, file.c_str(), i == selectorIndex ? 0 : 1);
|
||||
renderer.drawUiText(10, 50 + i * 30, file.c_str(), i != selectorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ void FullScreenMessageScreen::onEnter() {
|
||||
const auto left = (renderer.getPageWidth() - width) / 2;
|
||||
const auto top = (renderer.getPageHeight() - height) / 2;
|
||||
|
||||
renderer.clearScreen(invert);
|
||||
renderer.drawUiText(left, top, text.c_str(), invert ? 0 : 1, style);
|
||||
renderer.flushDisplay(partialUpdate);
|
||||
renderer.clearScreen();
|
||||
renderer.drawUiText(left, top, text.c_str(), true, style);
|
||||
renderer.flushDisplay(refreshMode);
|
||||
}
|
||||
|
||||
@@ -2,23 +2,22 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "EpdFontFamily.h"
|
||||
#include <EInkDisplay.h>
|
||||
#include <EpdFontFamily.h>
|
||||
#include "Screen.h"
|
||||
|
||||
class FullScreenMessageScreen final : public Screen {
|
||||
std::string text;
|
||||
EpdFontStyle style;
|
||||
bool invert;
|
||||
bool partialUpdate;
|
||||
EInkDisplay::RefreshMode refreshMode;
|
||||
|
||||
public:
|
||||
explicit FullScreenMessageScreen(EpdRenderer& renderer, InputManager& inputManager, std::string text,
|
||||
const EpdFontStyle style = REGULAR, const bool invert = false,
|
||||
const bool partialUpdate = true)
|
||||
const EpdFontStyle style = REGULAR,
|
||||
const EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH)
|
||||
: Screen(renderer, inputManager),
|
||||
text(std::move(text)),
|
||||
style(style),
|
||||
invert(invert),
|
||||
partialUpdate(partialUpdate) {}
|
||||
refreshMode(refreshMode) {}
|
||||
void onEnter() override;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
#include <EpdRenderer.h>
|
||||
|
||||
#include "images/SleepScreenImg.h"
|
||||
#include "images/CrossLarge.h"
|
||||
|
||||
void SleepScreen::onEnter() { renderer.drawImageNoMargin(SleepScreenImg, 0, 0, 800, 480, false, true); }
|
||||
void SleepScreen::onEnter() {
|
||||
const auto pageWidth = renderer.getPageWidth();
|
||||
const auto pageHeight = renderer.getPageHeight();
|
||||
|
||||
renderer.clearScreen();
|
||||
renderer.drawImage(CrossLarge, (pageHeight - 128) / 2, (pageWidth - 128) / 2, 128, 128);
|
||||
const int width = renderer.getUiTextWidth("CrossPoint", BOLD);
|
||||
renderer.drawUiText((pageWidth - width)/ 2, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
|
||||
const int bootingWidth = renderer.getSmallTextWidth("SLEEPING");
|
||||
renderer.drawSmallText((pageWidth - bootingWidth) / 2, pageHeight / 2 + 95, "SLEEPING");
|
||||
renderer.invertScreen();
|
||||
renderer.flushDisplay(EInkDisplay::FULL_REFRESH);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user