Custom rendering almost works
This commit is contained in:
@ -6,12 +6,22 @@
|
||||
* Drawing modes
|
||||
*/
|
||||
enum class Draw {
|
||||
Normal = 0, // set pixels to black, no fill
|
||||
Clear = DRAW_OPT_CLEAR_PIXELS,
|
||||
Xor = DRAW_OPT_LOGICAL_XOR,
|
||||
Fill = DRAW_OPT_FILL_SHAPE,
|
||||
Normal = 0x00, // set pixels to black, no fill
|
||||
Clear = 0x01,
|
||||
Xor = 0x02,
|
||||
Fill = 0x04,
|
||||
Transparent = 0x08,
|
||||
Double = 0x10,
|
||||
};
|
||||
|
||||
inline bool operator&(Draw a, Draw b) {
|
||||
return ((int)a & (int)b) != 0;
|
||||
}
|
||||
|
||||
inline Draw operator|(Draw a, Draw b) {
|
||||
return (Draw)((int)a | (int)b);
|
||||
}
|
||||
|
||||
enum class ScreenFont {
|
||||
Normal = FONTTYPE_NORMAL,
|
||||
Small = FONTTYPE_SMALL,
|
||||
@ -30,7 +40,6 @@ namespace screen {
|
||||
|
||||
static const uint8_t pixmap[] = {0x00, 0xE0, 0x1C, 0xFC, 0x03, 0xE3, 0x1F, 0xFF};
|
||||
static uint8_t bitBuffer[ROW_SIZE * LCD_HEIGHT];
|
||||
static uint8_t *mappedFrameBuffer;
|
||||
static bool dirty;
|
||||
|
||||
static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
|
||||
@ -53,7 +62,7 @@ static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
|
||||
pixels = *bitBuffer++ << 0;
|
||||
pixels |= *bitBuffer++ << 8;
|
||||
|
||||
bitBuffer += ROW_SIZE - 26;
|
||||
bitBuffer += ROW_SIZE - 23;
|
||||
|
||||
int m = 4;
|
||||
while (m--) {
|
||||
@ -63,12 +72,9 @@ static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
|
||||
}
|
||||
}
|
||||
|
||||
static void updateLCD() {
|
||||
bitBufferToFrameBuffer(bitBuffer, mappedFrameBuffer);
|
||||
}
|
||||
|
||||
#define OFF(x, y) (((y) << 5) + ((x) >> 3))
|
||||
#define MASK(x, y) (1 << ((x)&7))
|
||||
#define PIX2BYTES(x) (((x) + 7) >> 3)
|
||||
|
||||
static inline void applyMask(int off, int mask, Draw mode) {
|
||||
if (mode & Draw::Clear)
|
||||
@ -85,24 +91,24 @@ void _setPixel(int x, int y, Draw mode) {
|
||||
}
|
||||
|
||||
void blitLineCore(int x, int y, int w, uint8_t *data, Draw mode) {
|
||||
if (y < 0 || y >= LMS.LCD_HEIGHT)
|
||||
if (y < 0 || y >= LCD_HEIGHT)
|
||||
return;
|
||||
if (x + w <= 0)
|
||||
return;
|
||||
if (x >= LMS.LCD_WIDTH)
|
||||
if (x >= LCD_WIDTH)
|
||||
return;
|
||||
|
||||
int shift = x & 7;
|
||||
int off = OFF(x, y);
|
||||
int off0 = OFF(0, y);
|
||||
int off1 = OFF(LMS.LCD_WIDTH - 1, y);
|
||||
int off1 = OFF(LCD_WIDTH - 1, y);
|
||||
int x1 = x + w;
|
||||
int prev = 0;
|
||||
|
||||
while (x < x1 - 8) {
|
||||
int curr = *data++ << shift;
|
||||
if (off0 <= off && off <= off1)
|
||||
applyMask(off, curr | prev);
|
||||
applyMask(off, curr | prev, mode);
|
||||
off++;
|
||||
prev = curr >> 8;
|
||||
x += 8;
|
||||
@ -112,8 +118,10 @@ void blitLineCore(int x, int y, int w, uint8_t *data, Draw mode) {
|
||||
if (left > 0) {
|
||||
int curr = *data << shift;
|
||||
if (off0 <= off && off <= off1)
|
||||
applyMask(off, (curr | prev) & ((1 << left) - 1));
|
||||
applyMask(off, (curr | prev) & ((1 << left) - 1), mode);
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
//%
|
||||
@ -126,23 +134,69 @@ static uint8_t ones[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
bool isValidIcon(Buffer buf) {
|
||||
return buf->length >= 3 && buf->data[0] == 0xf0;
|
||||
}
|
||||
|
||||
static const uint8_t bitdouble[] = {
|
||||
0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
|
||||
};
|
||||
|
||||
/** Double size of an icon. */
|
||||
//%
|
||||
Buffer doubleIcon(Buffer buf) {
|
||||
if (!isValidIcon(buf))
|
||||
return NULL;
|
||||
int w = buf->data[1];
|
||||
if (w > 126)
|
||||
return NULL;
|
||||
int bw = PIX2BYTES(w);
|
||||
int h = (buf->length - 2) / bw;
|
||||
int bw2 = PIX2BYTES(w * 2);
|
||||
Buffer out = mkBuffer(NULL, 2 + bw2 * h * 2);
|
||||
out->data[0] = 0xf0;
|
||||
out->data[1] = w * 2;
|
||||
uint8_t *src = buf->data + 2;
|
||||
uint8_t *dst = out->data + 2;
|
||||
for (int i = 0; i < h; ++i) {
|
||||
for (int jj = 0; jj < 2; ++jj) {
|
||||
auto p = src;
|
||||
for (int j = 0; j < bw; ++j) {
|
||||
*dst++ = bitdouble[*p & 0xf];
|
||||
*dst++ = bitdouble[*p >> 4];
|
||||
p++;
|
||||
}
|
||||
}
|
||||
src += bw;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Draw an icon on the screen. */
|
||||
//%
|
||||
void drawIcon(int x, int y, Buffer buf, Draw mode) {
|
||||
if (buf->length < 2)
|
||||
if (!isValidIcon(buf))
|
||||
return;
|
||||
int pixwidth = buf->data[0];
|
||||
if (pixwidth > 100)
|
||||
return;
|
||||
int ptr = 1;
|
||||
int bytewidth = (pixwidth + 7) >> 3;
|
||||
if (mode & Draw::Double)
|
||||
buf = doubleIcon(buf);
|
||||
|
||||
int pixwidth = buf->data[1];
|
||||
int ptr = 2;
|
||||
int bytewidth = PIX2BYTES(pixwidth);
|
||||
pixwidth = min(pixwidth, LCD_WIDTH);
|
||||
while (ptr + bytewidth <= buf->length) {
|
||||
if (mode == Draw::Normal)
|
||||
if (mode & (Draw::Clear | Draw::Xor | Draw::Transparent)) {
|
||||
// no erase of background
|
||||
} else {
|
||||
blitLineCore(x, y, pixwidth, ones, Draw::Clear);
|
||||
}
|
||||
blitLineCore(x, y, pixwidth, &buf->data[ptr], mode);
|
||||
y++;
|
||||
ptr += bytewidth;
|
||||
}
|
||||
|
||||
if (mode & Draw::Double)
|
||||
decrRC(buf);
|
||||
}
|
||||
|
||||
/** Clear screen and reset font to normal. */
|
||||
@ -151,23 +205,62 @@ void clear() {
|
||||
memset(bitBuffer, 0, sizeof(bitBuffer));
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
//%
|
||||
void dump() {
|
||||
char buf[LCD_WIDTH + 1];
|
||||
FILE *f = fopen("/tmp/screen.txt", "w");
|
||||
for (int i = 0; i < LCD_HEIGHT; ++i) {
|
||||
for (int j = 0; j < LCD_WIDTH; ++j) {
|
||||
if (bitBuffer[OFF(j, i)] & MASK(j, i))
|
||||
buf[j] = '#';
|
||||
else
|
||||
buf[j] = '.';
|
||||
}
|
||||
buf[LCD_WIDTH] = 0;
|
||||
fprintf(f, "%s\n", buf);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
namespace pxt {
|
||||
static uint8_t *mappedFrameBuffer;
|
||||
|
||||
//%
|
||||
void updateLCD() {
|
||||
if (dirty && mappedFrameBuffer != MAP_FAILED) {
|
||||
dirty = false;
|
||||
bitBufferToFrameBuffer(bitBuffer, mappedFrameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void *screenRefresh(void *dummy) {
|
||||
while (true) {
|
||||
sleep_core_us(30000);
|
||||
LcdUpdate();
|
||||
updateLCD();
|
||||
}
|
||||
}
|
||||
|
||||
void screen_init() {
|
||||
LcdInitNoAutoRefresh();
|
||||
LcdClean();
|
||||
void init() {
|
||||
DMESG("init screen");
|
||||
if (mappedFrameBuffer)
|
||||
return;
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
DMESG("init screen %d", fd);
|
||||
mappedFrameBuffer = (uint8_t *)mmap(NULL, FB_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
DMESG("map %p", mappedFrameBuffer);
|
||||
if (mappedFrameBuffer == MAP_FAILED) {
|
||||
target_panic(111);
|
||||
}
|
||||
clear();
|
||||
|
||||
pthread_t pid;
|
||||
pthread_create(&pid, NULL, screenRefresh, NULL);
|
||||
pthread_detach(pid);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxt {
|
||||
void screen_init() {
|
||||
screen::init();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user