Add separate type for Icons (same repr as buffer)

This commit is contained in:
Michal Moskal 2017-10-30 13:04:12 +00:00
parent c085094394
commit f6e350cf9f
5 changed files with 149 additions and 88 deletions

View File

@ -27,6 +27,9 @@ class MMap : public RefObject {
extern volatile bool paniced;
// Buffer and Icon share representation.
typedef Buffer Icon;
}
#define DEVICE_EVT_ANY 0

View File

@ -130,82 +130,6 @@ void _blitLine(int xw, int y, Buffer buf, Draw mode) {
blitLineCore(XX(xw), y, YY(xw), buf->data, mode);
}
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,
};
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 (!isValidIcon(buf))
return;
if (mode & (Draw::Double | Draw::Quad)) {
buf = doubleIcon(buf);
if (mode & Draw::Quad) {
auto pbuf = buf;
buf = doubleIcon(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)
decrRC(buf);
}
/** Clear screen and reset font to normal. */
//%
void clear() {
@ -309,11 +233,23 @@ extern "C" void drawPanic(int code) {
updateLCD();
int fd = open("/dev/lms_ui", O_RDWR);
uint8_t cmd[] = { 48 + 5, 0 };
uint8_t cmd[] = {48 + 5, 0};
write(fd, cmd, 2);
close(fd);
}
bool isValidIcon(Buffer buf) {
return buf->length >= 3 && buf->data[0] == 0xf0;
}
/** Makes an icon bound to a buffer. */
//%
Icon iconOf(Buffer buf) {
if (!isValidIcon(buf))
return NULL;
incrRC(buf);
return buf;
}
}
namespace pxt {
@ -321,3 +257,105 @@ void screen_init() {
screen::init();
}
}
//% fixedInstances
namespace IconMethods {
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(Icon ic) {
incrRC(ic);
return ic;
}
/** Returns the width of an icon. */
//% property
int width(Icon ic) {
if (!isValidIcon(ic))
return 0;
return ic->data[1];
}
/** Returns the height of an icon. */
//% property
int height(Icon ic) {
if (!isValidIcon(ic))
return 0;
int bw = PIX2BYTES(ic->data[1]);
return (ic->length - 2) / bw;
}
/** Double size of an icon. */
//%
Icon doubled(Icon 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 draw(Icon buf, int x, int y, Draw mode) {
if (!isValidIcon(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);
}
}

View File

@ -27,7 +27,7 @@ namespace screen {
currFont = f
}
export const heart = hex`f007 367f7f3e1c08`
export const heart = iconOf(hex`f007 367f7f3e1c08`)
export function defaultFont(): Font {
return {
@ -112,6 +112,7 @@ namespace screen {
let byteWidth = (currFont.charWidth + 7) >> 3
let charSize = byteWidth * currFont.charHeight
let iconBuf = output.createBuffer(2 + charSize)
let icon = iconOf(iconBuf)
let double = (mode & Draw.Quad) ? 4 : (mode & Draw.Double) ? 2 : 1
iconBuf[0] = 0xf0
iconBuf[1] = currFont.charWidth
@ -127,7 +128,7 @@ namespace screen {
iconBuf.fill(0, 2)
else
iconBuf.write(2, currFont.data.slice(idx, charSize))
drawIcon(x, y, iconBuf, mode)
icon.draw(x, y, mode)
x += double * currFont.charWidth
}
}

35
libs/core/shims.d.ts vendored
View File

@ -78,17 +78,36 @@ declare namespace screen {
}
declare namespace screen {
/** Double size of an icon. */
//% shim=screen::doubleIcon
function doubleIcon(buf: Buffer): Buffer;
/** Draw an icon on the screen. */
//% shim=screen::drawIcon
function drawIcon(x: int32, y: int32, buf: Buffer, mode: Draw): void;
/** Clear screen and reset font to normal. */
//% shim=screen::clear
function clear(): void;
/** Makes an icon bound to a buffer. */
//% shim=screen::iconOf
function iconOf(buf: Buffer): Icon;
}
declare interface Icon {
/** Returns the underlaying Buffer object. */
//% property shim=IconMethods::buffer
buffer: Buffer;
/** Returns the width of an icon. */
//% property shim=IconMethods::width
width: int32;
/** Returns the height of an icon. */
//% property shim=IconMethods::height
height: int32;
/** Double size of an icon. */
//% shim=IconMethods::doubled
doubled(): Icon;
/** Draw an icon on the screen. */
//% shim=IconMethods::draw
draw(x: int32, y: int32, mode: Draw): void;
}
declare namespace output {

View File

@ -4,7 +4,7 @@ screen.print("PXT!", 10, 30, Draw.Quad)
screen.drawRect(40, 40, 20, 10, Draw.Fill)
output.setStatusLight(LightsPattern.Orange)
screen.drawIcon(100, 50, screen.doubleIcon(screen.heart), Draw.Double | Draw.Transparent)
screen.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
input.buttonEnter.onEvent(ButtonEvent.Click, () => {
screen.clear()