Skip to content

Commit

Permalink
sdk: implement interlacing
Browse files Browse the repository at this point in the history
keira: add optional interlacing for NES
  • Loading branch information
and3rson committed Apr 29, 2024
1 parent 85aad4d commit d8e9430
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 5 deletions.
4 changes: 3 additions & 1 deletion firmware/keira/src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ App::App(const char* name, uint16_t x, uint16_t y, uint16_t w, uint16_t h) :
isDrawQueued(false),
backCanvasMutex(xSemaphoreCreateMutex()),
stackSize(8192),
appCore(0) {
appCore(0),
frame(0) {
// Clear buffers
canvas->fillScreen(0);
backCanvas->fillScreen(0);
Expand Down Expand Up @@ -88,6 +89,7 @@ void App::queueDraw() {
canvas = backCanvas;
backCanvas = temp;
isDrawQueued = true;
frame++;
xSemaphoreGive(backCanvasMutex);
taskYIELD();
}
Expand Down
6 changes: 4 additions & 2 deletions firmware/keira/src/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
#include <Arduino.h>
#include <lilka.h>

typedef enum {
typedef enum : uint32_t {
APP_FLAG_NONE = 0,
APP_FLAG_FULLSCREEN = 1,
APP_FLAG_FULLSCREEN = 1 << 0,
APP_FLAG_INTERLACED = 1 << 1,
} AppFlags;

/// Клас, що представляє додаток для Кіри.
Expand Down Expand Up @@ -80,6 +81,7 @@ class App {
void releaseBackCanvas();

lilka::Canvas* backCanvas;
uint64_t frame;

private:
static void _run(void* data);
Expand Down
6 changes: 5 additions & 1 deletion firmware/keira/src/appmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ void AppManager::loop() {
renderToast(topApp->backCanvas);
}
if (app->needsRedraw()) {
lilka::display.drawCanvas(app->backCanvas);
if (app->flags & AppFlags::APP_FLAG_INTERLACED) {
lilka::display.drawCanvasInterlaced(app->backCanvas, app->frame % 2);
} else {
lilka::display.drawCanvas(app->backCanvas);
}
app->markClean();
}
app->releaseBackCanvas();
Expand Down
15 changes: 15 additions & 0 deletions firmware/keira/src/apps/nes/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,26 @@ void Driver::freeFrite(int numDirties, rect_t* dirtyRects) {
bmp_destroy(&bitmap);
}

bool odd = true;

void Driver::customBlit(bitmap_t* bmp, int numDirties, rect_t* dirtyRects) {
last_frame_duration = micros() - last_render;
last_render = micros();

lilka::Canvas* canvas = app->canvas;

#ifdef INTERLACED
for (int y = odd ? 1 : 0; y < frame_height; y += 2) {
const uint8_t* line = bmp->line[y];
for (int x = 0; x < frame_width; x++) {
uint8_t index = line[x];
uint16_t color = nesPalette[index];
canvas->writePixelPreclipped(x + frame_x, y + frame_y, color);
// app->canvas->drawPixel(x + frame_x, y + frame_y, color);
}
}
odd = !odd;
#else
for (int y = 0; y < frame_height; y++) {
const uint8_t* line = bmp->line[y];
for (int x = 0; x < frame_width; x++) {
Expand All @@ -91,6 +105,7 @@ void Driver::customBlit(bitmap_t* bmp, int numDirties, rect_t* dirtyRects) {
// app->canvas->drawPixel(x + frame_x, y + frame_y, color);
}
}
#endif

// Serial.println("Draw 1 took " + String(micros() - last_render) + "us");

Expand Down
5 changes: 5 additions & 0 deletions firmware/keira/src/apps/nes/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ extern "C" {
#include <nofconfig.h>
}

// Розкоментуйте, якщо ви хочете використовувати інтерлейс.
// Це збільшує FPS з ~30 до ~50 і дає більш ретро-вигляд та мерехтіння, але багатьом людям цей ефект може не сподобатися.
// Історично, більшість старих телевізорів використовували інтерлейс, тому цей ефект зробить гру більш автентичною.
// #define NESAPP_INTERLACED

class Driver {
public:
static void setNesApp(NesApp* app);
Expand Down
6 changes: 5 additions & 1 deletion firmware/keira/src/apps/nes/nesapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
NesApp::NesApp(String path) : App("NES", 0, 0, lilka::display.width(), lilka::display.height()) {
argv[0] = new char[path.length() + 1];
strcpy(argv[0], path.c_str());
setFlags(AppFlags::APP_FLAG_FULLSCREEN);
#ifdef NESAPP_INTERLACED
setFlags(static_cast<AppFlags>(AppFlags::APP_FLAG_FULLSCREEN | AppFlags::APP_FLAG_INTERLACED));
#else
setFlags(static_cast<AppFlags>(AppFlags::APP_FLAG_FULLSCREEN));
#endif
}

NesApp::~NesApp() {
Expand Down
9 changes: 9 additions & 0 deletions sdk/lib/lilka/src/lilka/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,15 @@ uint8_t* Display::getFont() {
return u8g2Font;
}

void Display::drawCanvasInterlaced(Canvas* canvas, bool odd) {
this->startWrite();
for (int y = odd ? 1 : 0; y < canvas->height(); y += 2) {
this->writeAddrWindow(canvas->x(), canvas->y() + y, canvas->width(), 1);
this->writePixels(canvas->getFramebuffer() + y * canvas->width(), canvas->width());
}
this->endWrite();
}

void Canvas::draw16bitRGBBitmapWithTranColor(
int16_t x, int16_t y, const uint16_t bitmap[], uint16_t transparent_color, int16_t w, int16_t h
) {
Expand Down
1 change: 1 addition & 0 deletions sdk/lib/lilka/src/lilka/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ class Display : public Arduino_ST7789, public GFX<Display> {
int16_t x, int16_t y, const uint16_t bitmap[], uint16_t transparent_color, int16_t w, int16_t h
);
uint8_t* getFont();
void drawCanvasInterlaced(Canvas* canvas, bool odd);

private:
const void* splash;
Expand Down

0 comments on commit d8e9430

Please sign in to comment.