Moving drawing code into TS
This commit is contained in:
parent
17a01b46be
commit
ce758a091e
@ -79,70 +79,31 @@ static inline void applyMask(int off, int mask, Draw mode) {
|
|||||||
bitBuffer[off] |= mask;
|
bitBuffer[off] |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setPixelCore(int x, int y, Draw mode) {
|
//%
|
||||||
|
void _setPixel(int x, int y, Draw mode) {
|
||||||
applyMask(OFF(x, y), MASK(x, y), mode);
|
applyMask(OFF(x, y), MASK(x, y), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setLineCore(int x0, int x1, int y, Draw mode) {
|
void blitLineCore(int x, int y, int w, uint8_t *data, Draw mode) {
|
||||||
while (x0 < x1 && (x0 & 7)) {
|
if (y < 0 || y >= LMS.LCD_HEIGHT)
|
||||||
setPixelCore(x0++, y, mode);
|
|
||||||
}
|
|
||||||
int off = OFF(x0, y);
|
|
||||||
// 8-aligned now
|
|
||||||
while (x0 < x1 - 8) {
|
|
||||||
applyMask(off++, 0xff, mode);
|
|
||||||
x0 += 8;
|
|
||||||
}
|
|
||||||
while (x0 < x1) {
|
|
||||||
setPixelCore(x0++, y, mode);
|
|
||||||
}
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawRect(int x, int y, int w, int h, Draw mode) {
|
|
||||||
if (x < 0) {
|
|
||||||
w += x;
|
|
||||||
x = 0;
|
|
||||||
}
|
|
||||||
if (y < 0) {
|
|
||||||
h += y;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
if (w <= 0)
|
|
||||||
return;
|
return;
|
||||||
if (h <= 0)
|
if (x + w <= 0)
|
||||||
return;
|
return;
|
||||||
int x1 = min(LCD_WIDTH, x + w);
|
if (x >= LMS.LCD_WIDTH)
|
||||||
int y1 = min(LCD_HEIGHT, y + h);
|
|
||||||
if (w == 1) {
|
|
||||||
while (y < y1)
|
|
||||||
setPixelCore(x, y++, mode);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
setLineCore(x, x1, y++, mode);
|
|
||||||
while (y < y1 - 1) {
|
|
||||||
if (mode & Draw::Fill) {
|
|
||||||
setLineCore(x, x1, y, mode);
|
|
||||||
} else {
|
|
||||||
setPixelCore(x, y, mode);
|
|
||||||
setPixelCore(x1 - 1, y, mode);
|
|
||||||
}
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if (y < y1)
|
|
||||||
setLineCore(x, x1, y, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void blitLine(int x, int y, int w, uint8_t *data, Draw mode) {
|
|
||||||
int shift = x & 7;
|
int shift = x & 7;
|
||||||
int off = OFF(x, y);
|
int off = OFF(x, y);
|
||||||
|
int off0 = OFF(0, y);
|
||||||
|
int off1 = OFF(LMS.LCD_WIDTH - 1, y);
|
||||||
int x1 = x + w;
|
int x1 = x + w;
|
||||||
int prev = 0;
|
int prev = 0;
|
||||||
|
|
||||||
while (x < x1 - 8) {
|
while (x < x1 - 8) {
|
||||||
int curr = *data++ << shift;
|
int curr = *data++ << shift;
|
||||||
applyMask(off++, curr | prev);
|
if (off0 <= off && off <= off1)
|
||||||
|
applyMask(off, curr | prev);
|
||||||
|
off++;
|
||||||
prev = curr >> 8;
|
prev = curr >> 8;
|
||||||
x += 8;
|
x += 8;
|
||||||
}
|
}
|
||||||
@ -150,64 +111,45 @@ void blitLine(int x, int y, int w, uint8_t *data, Draw mode) {
|
|||||||
int left = x1 - x;
|
int left = x1 - x;
|
||||||
if (left > 0) {
|
if (left > 0) {
|
||||||
int curr = *data << shift;
|
int curr = *data << shift;
|
||||||
|
if (off0 <= off && off <= off1)
|
||||||
applyMask(off, (curr | prev) & ((1 << left) - 1));
|
applyMask(off, (curr | prev) & ((1 << left) - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update a pixel on the screen. */
|
|
||||||
//%
|
//%
|
||||||
void setPixel(int x, int y, Draw mode) {
|
void _blitLine(int xw, int y, Buffer buf, Draw mode) {
|
||||||
if (0 <= x && x < LCD_WIDTH && 0 <= y && y <= LCD_HEIGHT) {
|
blitLineCore(XX(xw), y, YY(xw), buf->data, mode);
|
||||||
setPixelCore(x, y, mode);
|
}
|
||||||
dirty = true;
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Draw an icon on the screen. */
|
||||||
|
//%
|
||||||
|
void drawIcon(int x, int y, Buffer buf, Draw mode) {
|
||||||
|
if (buf->length < 2)
|
||||||
|
return;
|
||||||
|
int pixwidth = buf->data[0];
|
||||||
|
if (pixwidth > 100)
|
||||||
|
return;
|
||||||
|
int ptr = 1;
|
||||||
|
int bytewidth = (pixwidth + 7) >> 3;
|
||||||
|
while (ptr + bytewidth <= buf->length) {
|
||||||
|
if (mode == Draw::Normal)
|
||||||
|
blitLineCore(x, y, pixwidth, ones, Draw::Clear);
|
||||||
|
blitLineCore(x, y, pixwidth, &buf->data[ptr], mode);
|
||||||
|
y++;
|
||||||
|
ptr += bytewidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//%
|
|
||||||
void _drawRect(uint32_t p0, uint32_t p1, Draw mode) {
|
|
||||||
drawRect(XX(p0), YY(p0), XX(p1), YY(p1), mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fontFirst, fontWidth, fontHeight, fontByteWidth;
|
|
||||||
static uint8_t *fontChars;
|
|
||||||
static Buffer currFont;
|
|
||||||
|
|
||||||
/** Set font. */
|
|
||||||
//%
|
|
||||||
void setFont(Buffer font) {
|
|
||||||
if (!font || font->length < 100)
|
|
||||||
return;
|
|
||||||
if (font->data[0] != 0xf0 || font->data[1] != 0x42)
|
|
||||||
return;
|
|
||||||
fontFirst = font->data[2];
|
|
||||||
fontWidth = font->data[3];
|
|
||||||
fontHeight = font->data[4];
|
|
||||||
fontByteWidth = (fontWidth + 7) / 8;
|
|
||||||
fontChars = &font->data[8];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Draw text. */
|
|
||||||
//% mode.defl=0
|
|
||||||
void drawText(int x, int y, String text, Draw mode) {
|
|
||||||
LcdText((int)mode & (int)Draw::Clear ? 0 : 1, x, y, text->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clear screen and reset font to normal. */
|
/** Clear screen and reset font to normal. */
|
||||||
//%
|
//%
|
||||||
void clear() {
|
void clear() {
|
||||||
LcdClearDisplay();
|
memset(bitBuffer, 0, sizeof(bitBuffer));
|
||||||
}
|
dirty = true;
|
||||||
|
|
||||||
/** Scroll screen vertically. */
|
|
||||||
//%
|
|
||||||
void scroll(int v) {
|
|
||||||
LcdScroll(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set font for drawText() */
|
|
||||||
//%
|
|
||||||
void setFont(ScreenFont font) {
|
|
||||||
LcdSelectFont((uint8_t)font);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,30 +1,127 @@
|
|||||||
namespace screen {
|
namespace screen {
|
||||||
//% shim=screen::_drawLine
|
//% shim=screen::setPixelCore
|
||||||
function _drawLine(p0: uint32, p1: uint32, mode: Draw): void { }
|
function setPixelCore(p0: uint32, p1: uint32, mode: Draw): void { }
|
||||||
|
|
||||||
//% shim=screen::_drawRect
|
//% shim=screen::blitLine
|
||||||
function _drawRect(p0: uint32, p1: uint32, mode: Draw): void { }
|
function blitLine(xw: uint32, y: uint32, buf: Buffer, mode: Draw): void { }
|
||||||
|
|
||||||
//% shim=screen::_drawEllipse
|
|
||||||
function _drawEllipse(p0: uint32, p1: uint32, mode: Draw): void { }
|
|
||||||
|
|
||||||
function pack(x: number, y: number) {
|
function pack(x: number, y: number) {
|
||||||
return Math.clamp(0, 512, x) | (Math.clamp(0, 512, y) << 16)
|
return Math.clamp(0, 512, x) | (Math.clamp(0, 512, y) << 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawLine(x0: number, y0: number, x1: number, y1: number, mode?: Draw) {
|
const ones = hex`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
|
||||||
_drawLine(pack(x0, y0), pack(x1, y1), mode)
|
|
||||||
|
function setLineCore(x: number, x1: number, y: number, mode: Draw) {
|
||||||
|
blitLine(pack(x, x1 - x), y, ones, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawRect(x: number, y: number, w: number, h: number, mode?: Draw) {
|
export interface Font {
|
||||||
_drawRect(pack(x, y), pack(w, h), mode)
|
charWidth: number;
|
||||||
|
charHeight: number;
|
||||||
|
firstChar: number;
|
||||||
|
data: Buffer;
|
||||||
|
}
|
||||||
|
let currFont: Font
|
||||||
|
|
||||||
|
export const heart = hex`07 367f7f3e1c08`
|
||||||
|
|
||||||
|
export function defaultFont(): Font {
|
||||||
|
return {
|
||||||
|
charWidth: 8,
|
||||||
|
charHeight: 8,
|
||||||
|
firstChar: 32,
|
||||||
|
// source https://github.com/dhepper/font8x8
|
||||||
|
data: hex`
|
||||||
|
0000000000000000 183C3C1818001800 3636000000000000 36367F367F363600 0C3E031E301F0C00 006333180C666300
|
||||||
|
1C361C6E3B336E00 0606030000000000 180C0606060C1800 060C1818180C0600 00663CFF3C660000 000C0C3F0C0C0000
|
||||||
|
00000000000C0C06 0000003F00000000 00000000000C0C00 6030180C06030100 3E63737B6F673E00 0C0E0C0C0C0C3F00
|
||||||
|
1E33301C06333F00 1E33301C30331E00 383C36337F307800 3F031F3030331E00 1C06031F33331E00 3F3330180C0C0C00
|
||||||
|
1E33331E33331E00 1E33333E30180E00 000C0C00000C0C00 000C0C00000C0C06 180C0603060C1800 00003F00003F0000
|
||||||
|
060C1830180C0600 1E3330180C000C00 3E637B7B7B031E00 0C1E33333F333300 3F66663E66663F00 3C66030303663C00
|
||||||
|
1F36666666361F00 7F46161E16467F00 7F46161E16060F00 3C66030373667C00 3333333F33333300 1E0C0C0C0C0C1E00
|
||||||
|
7830303033331E00 6766361E36666700 0F06060646667F00 63777F7F6B636300 63676F7B73636300 1C36636363361C00
|
||||||
|
3F66663E06060F00 1E3333333B1E3800 3F66663E36666700 1E33070E38331E00 3F2D0C0C0C0C1E00 3333333333333F00
|
||||||
|
33333333331E0C00 6363636B7F776300 6363361C1C366300 3333331E0C0C1E00 7F6331184C667F00 1E06060606061E00
|
||||||
|
03060C1830604000 1E18181818181E00 081C366300000000 00000000000000FF 0C0C180000000000 00001E303E336E00
|
||||||
|
0706063E66663B00 00001E3303331E00 3830303e33336E00 00001E333f031E00 1C36060f06060F00 00006E33333E301F
|
||||||
|
0706366E66666700 0C000E0C0C0C1E00 300030303033331E 070666361E366700 0E0C0C0C0C0C1E00 0000337F7F6B6300
|
||||||
|
00001F3333333300 00001E3333331E00 00003B66663E060F 00006E33333E3078 00003B6E66060F00 00003E031E301F00
|
||||||
|
080C3E0C0C2C1800 0000333333336E00 00003333331E0C00 0000636B7F7F3600 000063361C366300 00003333333E301F
|
||||||
|
00003F190C263F00 380C0C070C0C3800 1818180018181800 070C0C380C0C0700 6E3B000000000000 0000000000000000
|
||||||
|
`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawEllipse(x: number, y: number, rx: number, ry: number, mode?: Draw) {
|
export function setPixel(x: number, y: number, mode = Draw.Normal) {
|
||||||
_drawEllipse(pack(x, y), pack(rx, ry), mode)
|
x |= 0
|
||||||
|
y |= 0
|
||||||
|
if (0 <= x && x < LMS.LCD_WIDTH && 0 <= y && y < LMS.LCD_HEIGHT)
|
||||||
|
setPixelCore(x, y, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawCircle(x: number, y: number, r: number, mode?: Draw) {
|
export function drawText(x: number, y: number, text: string, mode = Draw.Normal) {
|
||||||
drawEllipse(x, y, r, r, mode)
|
x |= 0
|
||||||
|
y |= 0
|
||||||
|
if (!currFont) currFont = defaultFont()
|
||||||
|
let x0 = x
|
||||||
|
let cp = 0
|
||||||
|
let byteWidth = (currFont.charWidth + 7) >> 3
|
||||||
|
let iconBuf = output.createBuffer(1 + byteWidth * currFont.charHeight)
|
||||||
|
iconBuf[0] = currFont.charWidth
|
||||||
|
while (cp < text.length) {
|
||||||
|
let ch = text.charCodeAt(cp++)
|
||||||
|
if (ch == 10) {
|
||||||
|
y += currFont.charHeight + 2
|
||||||
|
x = x0
|
||||||
}
|
}
|
||||||
|
if (ch < 32) continue
|
||||||
|
let idx = (ch - currFont.firstChar) * byteWidth
|
||||||
|
if (idx < 0 || idx + iconBuf.length - 1 > currFont.data.length)
|
||||||
|
iconBuf.fill(0, 1)
|
||||||
|
else
|
||||||
|
iconBuf.write(1, currFont.data.slice(idx, byteWidth))
|
||||||
|
drawIcon(x, y, iconBuf, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function drawRect(x: number, y: number, w: number, h: number, mode = Draw.Normal) {
|
||||||
|
x |= 0;
|
||||||
|
y |= 0;
|
||||||
|
w |= 0;
|
||||||
|
h |= 0;
|
||||||
|
if (x < 0) {
|
||||||
|
w += x;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
h += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
if (w <= 0)
|
||||||
|
return;
|
||||||
|
if (h <= 0)
|
||||||
|
return;
|
||||||
|
let x1 = Math.min(LMS.LCD_WIDTH, x + w);
|
||||||
|
let y1 = Math.min(LMS.LCD_HEIGHT, y + h);
|
||||||
|
if (w == 1) {
|
||||||
|
while (y < y1)
|
||||||
|
setPixelCore(x, y++, mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLineCore(x, x1, y++, mode);
|
||||||
|
while (y < y1 - 1) {
|
||||||
|
if (mode & Draw.Fill) {
|
||||||
|
setLineCore(x, x1, y, mode);
|
||||||
|
} else {
|
||||||
|
setPixelCore(x, y, mode);
|
||||||
|
setPixelCore(x1 - 1, y, mode);
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
if (y < y1)
|
||||||
|
setLineCore(x, x1, y, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user