Integrate screen APIs from common packages (#343)

* starting screen api intergration

* Further image integration

* Aligning with new screen apis

* Build fixes

* Adjust to common screen state

* Fix unpackPNG

* Add game library

* Optimize screen rendering

* bumping common packages

* updated shims

* moving images into ev3

* upgrading to common packages

* added try/use

* cap

* fixed tryp age
This commit is contained in:
Michał Moskal
2018-02-26 23:16:17 +00:00
committed by Peli de Halleux
parent 5bd9705966
commit c2d26a8418
23 changed files with 733 additions and 908 deletions

View File

@ -9,39 +9,12 @@
#include <fcntl.h>
#include <sys/ioctl.h>
/**
* Drawing modes
*/
enum class Draw {
Normal = 0x00, // set pixels to black, no fill
Clear = 0x01,
Xor = 0x02,
Fill = 0x04,
Transparent = 0x08,
Double = 0x10,
Quad = 0x20,
};
namespace pxt {
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);
}
#define XX(v) ((uint32_t)(v)&0xffff)
#define YY(v) ((uint32_t)(v) >> 16)
// We only support up to 4 arguments for C++ functions - need to pack them on the TS side
namespace screen {
#define ROW_SIZE 32
#define ROW_SIZE 23
#define FB_SIZE (60 * LCD_HEIGHT)
static const uint8_t pixmap[] = {0x00, 0xE0, 0x1C, 0xFC, 0x03, 0xE3, 0x1F, 0xFF};
static uint8_t bitBuffer[ROW_SIZE * LCD_HEIGHT];
static bool dirty;
static const uint8_t pixmap[] = {0x00, 0x03, 0x1C, 0x1F, 0xE0, 0xE3, 0xFC, 0xFF};
static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
uint32_t pixels;
@ -49,129 +22,48 @@ static void bitBufferToFrameBuffer(uint8_t *bitBuffer, uint8_t *fb) {
for (int line = 0; line < LCD_HEIGHT; line++) {
int n = 7;
while (n--) {
pixels = *bitBuffer++ << 0;
pixels = *bitBuffer++ << 16;
pixels |= *bitBuffer++ << 8;
pixels |= *bitBuffer++ << 16;
pixels |= *bitBuffer++ << 0;
int m = 8;
while (m--) {
*fb++ = pixmap[pixels & 0x07];
pixels >>= 3;
*fb++ = pixmap[(pixels >> 21) & 0x07];
pixels <<= 3;
}
}
pixels = *bitBuffer++ << 0;
pixels |= *bitBuffer++ << 8;
bitBuffer += ROW_SIZE - 23;
pixels = *bitBuffer++ << 8;
pixels |= *bitBuffer++ << 0;
int m = 4;
while (m--) {
*fb++ = pixmap[pixels & 0x07];
pixels >>= 3;
*fb++ = pixmap[(pixels >> 13) & 0x07];
pixels <<= 3;
}
}
}
#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)
bitBuffer[off] &= ~mask;
else if (mode & Draw::Xor)
bitBuffer[off] ^= mask;
else
bitBuffer[off] |= mask;
}
//%
void _setPixel(int x, int y, Draw mode) {
applyMask(OFF(x, y), MASK(x, y), mode);
}
void blitLineCore(int x, int y, int w, uint8_t *data, Draw mode) {
if (y < 0 || y >= LCD_HEIGHT)
return;
if (x + w <= 0)
return;
if (x >= LCD_WIDTH)
return;
int shift = x & 7;
int off = OFF(x, y);
int off0 = OFF(0, y);
int off1 = OFF(LCD_WIDTH - 1, y);
int x1 = x + w + shift;
int prev = 0;
while (x < x1 - 8) {
int curr = *data++ << shift;
if (off0 <= off && off <= off1)
applyMask(off, curr | prev, mode);
off++;
prev = curr >> 8;
x += 8;
}
int left = x1 - x;
if (left > 0) {
int curr = *data << shift;
if (off0 <= off && off <= off1)
applyMask(off, (curr | prev) & ((1 << left) - 1), mode);
}
dirty = true;
}
//%
void _blitLine(int xw, int y, Buffer buf, Draw mode) {
blitLineCore(XX(xw), y, YY(xw), buf->data, mode);
}
/** Clear screen and reset font to normal. */
//%
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);
}
static uint8_t *mappedFrameBuffer;
static Image lastImg;
//%
void updateLCD() {
if (dirty && mappedFrameBuffer != MAP_FAILED) {
dirty = false;
bitBufferToFrameBuffer(bitBuffer, mappedFrameBuffer);
void updateScreen(Image img) {
if (img && img != lastImg) {
decrRC(lastImg);
incrRC(img);
lastImg = img;
}
if (lastImg && lastImg->isDirty() && mappedFrameBuffer != MAP_FAILED) {
if (lastImg->bpp() != 1 || lastImg->width() != LCD_WIDTH || lastImg->height() != LCD_HEIGHT)
target_panic(906);
lastImg->clearDirty();
bitBufferToFrameBuffer(lastImg->pix(), mappedFrameBuffer);
}
}
void *screenRefresh(void *dummy) {
while (true) {
sleep_core_us(30000);
updateLCD();
}
}
void init() {
void screen_init() {
DMESG("init screen");
if (mappedFrameBuffer)
return;
@ -182,25 +74,19 @@ void init() {
if (mappedFrameBuffer == MAP_FAILED) {
target_panic(903);
}
clear();
pthread_t pid;
pthread_create(&pid, NULL, screenRefresh, NULL);
pthread_detach(pid);
}
static const uint8_t numbers[] = {
0x06, 0x09, 0x09, 0x09, 0x06, 0x04, 0x06, 0x04, 0x04, 0x0e, 0x07, 0x08, 0x06, 0x01, 0x0f, 0x0f,
0x08, 0x04, 0x09, 0x06, 0x0c, 0x0a, 0x09, 0x1f, 0x08, 0x1f, 0x01, 0x0f, 0x10, 0x0f, 0x08, 0x04,
0x0e, 0x11, 0x0e, 0x1f, 0x08, 0x04, 0x02, 0x01, 0x0e, 0x11, 0x0e, 0x11, 0x0e, 0x0e, 0x11, 0x0e,
0x04, 0x02,
// face
0b11011, 0b11011, 0b00000, 0b11111, 0b11011,
0x06, 0x09, 0x09, 0x09, 0x06, 0x04, 0x06, 0x04, 0x04, 0x0e, 0x07, 0x08, 0x06,
0x01, 0x0f, 0x0f, 0x08, 0x04, 0x09, 0x06, 0x0c, 0x0a, 0x09, 0x1f, 0x08, 0x1f,
0x01, 0x0f, 0x10, 0x0f, 0x08, 0x04, 0x0e, 0x11, 0x0e, 0x1f, 0x08, 0x04, 0x02,
0x01, 0x0e, 0x11, 0x0e, 0x11, 0x0e, 0x0e, 0x11, 0x0e, 0x04, 0x02,
0x1b, 0x1b, 0x00, 0x1f, 0x1b,
};
static void drawNumber(int off, int idx) {
static void drawNumber(uint8_t *dst, int idx) {
const uint8_t *src = &numbers[idx * 5];
uint8_t *dst = &bitBuffer[off];
for (int i = 0; i < 5; i++) {
uint8_t ch = *src++;
for (int jj = 0; jj < 8; ++jj) {
@ -215,13 +101,19 @@ static void drawNumber(int off, int idx) {
}
extern "C" void drawPanic(int code) {
clear();
int fd = open("/dev/lms_ui", O_RDWR);
uint8_t cmd[] = {48 + 5, 0};
write(fd, cmd, 2);
close(fd);
int ptr = ROW_SIZE * 16 + 3 + 6;
uint8_t bitBuffer[ROW_SIZE * LCD_HEIGHT];
memset(bitBuffer, 0, sizeof(bitBuffer));
auto ptr = &bitBuffer[ROW_SIZE * 16 + 3 + 6];
drawNumber(ptr, 10);
ptr += 6;
ptr = ROW_SIZE * 70 + 3;
ptr = &bitBuffer[ROW_SIZE * 70 + 3];
drawNumber(ptr, (code / 100) % 10);
ptr += 6;
@ -230,132 +122,9 @@ extern "C" void drawPanic(int code) {
drawNumber(ptr, (code / 1) % 10);
ptr += 6;
updateLCD();
int fd = open("/dev/lms_ui", O_RDWR);
uint8_t cmd[] = {48 + 5, 0};
write(fd, cmd, 2);
close(fd);
}
bool isValidImage(Buffer buf) {
return buf != NULL && buf->length >= 3 && buf->data[0] == 0xf0;
}
/** Makes an image bound to a buffer. */
//%
Image imageOf(Buffer buf) {
if (!isValidImage(buf))
return NULL;
incrRC(buf);
return buf;
}
}
namespace pxt {
void screen_init() {
screen::init();
}
}
//% fixedInstances
namespace ImageMethods {
using namespace screen;
static const uint8_t bitdouble[] = {
0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
};
static uint8_t ones[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/** Returns the underlaying Buffer object. */
//% property
Buffer buffer(Image ic) {
incrRC(ic);
return ic;
}
/** Returns the width of an image. */
//% property
int width(Image ic) {
if (!isValidImage(ic))
return 0;
return ic->data[1];
}
/** Returns the height of an image. */
//% property
int height(Image ic) {
if (!isValidImage(ic))
return 0;
int bw = PIX2BYTES(ic->data[1]);
return (ic->length - 2) / bw;
}
/** Double size of an image. */
//%
Image doubled(Image buf) {
if (!isValidImage(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;
if (mappedFrameBuffer != MAP_FAILED) {
bitBufferToFrameBuffer(bitBuffer, mappedFrameBuffer);
}
return out;
}
/** Draw an image on the screen. */
//%
void draw(Image buf, int x, int y, Draw mode) {
if (!isValidImage(buf))
return;
if (mode & (Draw::Double | Draw::Quad)) {
buf = doubled(buf);
if (mode & Draw::Quad) {
auto pbuf = buf;
buf = doubled(buf);
decrRC(pbuf);
}
}
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::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 | Draw::Quad))
decrRC(buf);
}
}
} // namespace pxt