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

@ -7,14 +7,14 @@
{
"name": "Try",
"imageUrl": "/static/lessons/try.png",
"description": "TBD",
"description": "Get a quick introduction to programming with EV3.",
"url": "/getting-started/try",
"cardType": "side"
},
{
"name": "use",
"name": "Use",
"imageUrl": "/static/lessons/use.png",
"description": "TBD",
"description": "Build a robot and drive into the world of robotics!",
"url": "/getting-started/use",
"cardType": "side"
}

178
docs/getting-started/try.md Normal file
View File

@ -0,0 +1,178 @@
# Try
[IMG: Neutral Image Display on EV3 Brick with Music Notes]
Get a quick introduction to programming with EV3.
We are excited to help you get started with LEGO MINDSTORMS Education EV3. In this project we will guide you through connecting your EV3 brick, creating your first program, controlling a Large Motor, a Touch Sensor and a Color Sensor. These steps can take up to 45 minutes.
## Turn on your EV3 Brick
[IMG: Hand pressing power button, Neutral Image Display, EV3 Brick]
Power on your EV3 Brick by pressing the Center Button.
## Connect Your EV3 Brick to Your Device
[IMG: Hand on cable & computer, Neutral Image Display, EV3 Brick]
Use the USB cable to connect your EV3 Brick to your device.
## Create and Run your First Program
[IMG: Try Program Blocks (see JavaScript below)]
1 - Create the program shown here:
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
brick.showMood(moods.neutral)
music.playSoundEffect(sounds.communicationHello)
})
```
* Drag a Brick Screen show mood block inside the on button block
* Change mood to
```block
brick.showMood(moods.neutral)
```
* Drag a Music play sound effect block below the show mood block
* Change sound effect to
```block
music.playSoundEffect(sounds.communicationHello)
```
2 Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## ~ hint
Note: Click here for help and more information about the programming blocks.
## ~
## Did It Work?
[IMG: Neutral Image Display, EV3 Brick]
Verify that the program you just created shows eyes on the Brick Display, and that the EV3 Brick played the sound “Hello!”
**Well done!**
## Connect a Large Motor
[IMG: EV3 Brick with hands connecting Large Motor to Port D]
Now you will learn to control the Large Motor.
Connect a Large Motor to Port D of your EV3 Brick using any of the connector cables.
## Create and Run This Program
[IMG: Program Blocks (see JavaScript below)]
1) Create the program shown here:
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
motors.largeD.run(50, 1, MoveUnit.Rotations)
})
```
* Start a new program
* Drag a run large A motor block inside the on button block
* Change large A to large D motors.largeD.run(50)
* Click on the + sign
* Change to 1 rotation
2) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## Did It Rotate?
[IMG: Large Motor D w/Rotating “WHRRR,” Hand, EV3 Brick]
Confirm that your motor has turned one rotation at power level 50 before stopping.
Download and run the program as many times as you want in order to verify this, or tinker with different power levels and different rotations.
## Connect a Touch Sensor
[IMG: Hands connecting Touch Sensor to Port 1 on EV3 Brick]
We will now control the Large Motor using a Touch Sensor.
Keeping the Large Motor connected to **Port D**, connect a Touch Sensor to **Port 1** of your EV3 Brick.
## Modify Your Program
[IMG: Program Blocks (see JavaScript below)]
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
sensors.touch1.pauseUntil(ButtonEvent.Pressed)
motors.largeD.run(50, 1, MoveUnit.Rotations)
})
```
1) Add a pause until touch 1 pressed Sensor block on top of the run large D Motor block
```block
sensors.touch1.pauseUntil(ButtonEvent.Pressed)
```
2) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## Press the Touch Sensor
[IMG: Hand Touch Sensor Pressed & EV3 Brick & Large Motor]
Confirm that the Large Motor has turned one rotation AFTER you press the Touch Sensor.
Download and run the program as many times as you want in order to verify this, or tinker with different Touch Sensor and Large Motor values.
## Connect a Color Sensor
[IMG: Hand connecting Color Sensor to Port 4, Large Motor D, EV3 Brick]
Now we will try to control the Large Motor using another sensor.
Keeping the Large Motor connected to **Port D**, connect the Color Sensor to **Port 4**.
Modify Your Program
[IMG: Program Blocks (see JavaScript below)]
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
sensors.color3.pauseForColor(ColorSensorColor.Green)
motors.largeD.run(50, 1, MoveUnit.Rotations)
})
```
1) Using the same program, replace the pause until touch 1 block with a pause color 3 for color block
```block
sensors.color3.pauseForColor(ColorSensorColor.Green)
```
2) Select the color you want to detect (e.g., green).
3) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## Place a Colored Brick in Front of the Color Sensor
[IMG: Colored bricks in front of Color Sensor, hands, EV3 Brick]
Confirm that the Large Motor has turned one rotation AFTER the Color Sensor has detected the colored brick.
Download and run the program as many times as you want in order to verify this, or tinker with different Color Sensor and Large Motor values.
Click on the JavaScript tab and change the color the Color Sensor detects to Black, Blue, Green, Yellow, Red, White, or Brown. Use Title Case for the color names.
## Well Done!
[IMG: EV3 Driving Base]
You have now learned how to control some of the inputs and outputs of the EV3.

114
docs/getting-started/use.md Normal file
View File

@ -0,0 +1,114 @@
# Use
[IMG: EV3 Driving Base full w/cuboid]
Build a robot and drive into the world of robotics!
In this project we will guide you through building a Driving Base Robot and programming it to move straight and turn. You will also build and Object Detector Module, and program it to detect an object. Its a good idea to have done the [Try](/getting-started/try) sequence first.
## Connect
[IMG: Apple Picker]
What if your school had a multipurpose robot? How would you use it?
Would you use it to clean the school or plant trees?
## Build Your Driving Base Robot
[IMG: EV3 Driving Base Building Instructions Cover Image]
* [Building instructions](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-driving-base-79bebfc16bd491186ea9c9069842155e.pdf)
## Make It Move
[IMG: Program Blocks (see JavaScript below)]
1) Create a program that makes the Driving Base move forward and stop at the finish line, which is 1 meter away.
Start by building this program:
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
motors.largeBC.steer(0, 50, 1, MoveUnit.Rotations)
})
```
* Drag a steer large B+C motor block inside the on button block
* Click on the + sign
* Change to 1 rotation
### ~ hint
Hint: You will have to modify the number of rotations until you find the number that matches the robot moving forward 1 meter and stopping.
### ~
2) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## Make It Turn
[IMG: Program Blocks (see JavaScript below)]
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
motors.largeBC.steer(-50, 50, 1, MoveUnit.Rotations)
})
```
1) Create a new program that turns the Driving Base 180 degrees.
### ~ hint
Hint: You will have to modify the turn ratio and the number of rotations until the robot reaches 180 degrees.
### ~
2) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
## Add an Ultrasonic Sensor to Your Driving Base
[IMG: EV3 Ultrasonic Sensor Driving Base Building Instructions Main Image]
* [building instructions](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-ultrasonic-sensor-driving-base-61ffdfa461aee2470b8ddbeab16e2070.pdf)
## Detect an Object
[IMG: Program Blocks (see JavaScript below)]
1 - Create a program that moves the Driving Base and makes it stop ``6`` cm from the Cuboid.
Create a new program
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
motors.largeBC.tank(50, 50)
sensors.ultrasonic4.setThreshold(UltrasonicSensorEvent.ObjectDetected, 6)
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectDetected);
motors.stopAll()
})
```
* Drag a tank large B+C motor block inside the on button block
* Drag a threshold Ultrasonic Sensor block and place below the motor block
* Drag a stop all motors block and place it below the sensor block
### ~ hint
Hint: You will have to modify the values of the Ultrasonic Sensor block until the robot reaches the desired position.
### ~
2) Click Download and follow the instructions to get your code onto your EV3 Brick. Press the center button on the EV3 Brick to run the program.
Click on the JavaScript tab and change and test the number value of the Ultrasonic Sensor
```typescript
sensors.ultrasonic4.setThreshold(UltrasonicSensorEvent.ObjectDetected, 10)
```
[IMG: EV3 Ultrasonic Sensor Driving Base Building Instructions Main Image]
**Congratulations!**
You are ready to move on to the next steps.
Try a LEGO MINDSTORMS Design Engineering, Coding, or Maker activity.

View File

@ -64,6 +64,15 @@ declare interface Buffer {
//% shim=BufferMethods::write
write(dstOffset: int32, src: Buffer): void;
}
declare namespace control {
/**
* Create a new zero-initialized buffer.
* @param size number of bytes in the buffer
*/
//% shim=control::createBuffer
function createBuffer(size: int32): Buffer;
}
declare namespace loops {
/**

View File

@ -53,11 +53,11 @@ namespace console {
//% weight=1
//% help=console/send-to-screen
export function sendToScreen(): void {
console.screen.attach();
console._screen.attach();
}
}
namespace console.screen {
namespace console._screen {
const maxLines = 100;
const screenLines = 10;
let lines: string[];
@ -78,7 +78,7 @@ namespace console.screen {
for (let i = 0; i < screenLines; ++i) {
const line = lines[i + scrollPosition];
if (line)
brick.print(line, 0, 4 + i * brick.LINE_HEIGHT)
screen.print(line, 0, 4 + i * brick.LINE_HEIGHT)
}
}

15
libs/core/enums.d.ts vendored
View File

@ -11,19 +11,4 @@
End = 2,
}
/**
* Drawing modes
*/
declare const enum Draw {
Normal = 0x00,
Clear = 0x01,
Xor = 0x02,
Fill = 0x04,
Transparent = 0x08,
Double = 0x10,
Quad = 0x20,
}
// Auto-generated. Do not edit. Really.

View File

@ -19,20 +19,13 @@ struct PNGHeader {
uint8_t IDAT[4];
} __attribute__((packed));
namespace screen {
namespace image {
static uint32_t swap(uint32_t num) {
return ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | ((num >> 8) & 0xff00) |
((num << 24) & 0xff000000);
}
static uint8_t revbits(uint8_t v) {
v = (v & 0xf0) >> 4 | (v & 0x0f) << 4;
v = (v & 0xcc) >> 2 | (v & 0x33) << 2;
v = (v & 0xaa) >> 1 | (v & 0x55) << 1;
return v;
}
/** Decompresses a 1-bit gray scale PNG image to image format. */
//%
Image unpackPNG(Buffer png) {
@ -101,12 +94,11 @@ Image unpackPNG(Buffer png) {
return NULL;
}
Buffer res = mkBuffer(NULL, 2 + byteW * hd.height);
res->data[0] = 0xf0;
res->data[1] = hd.width;
uint8_t *dst = res->data + 2;
auto res = mkImage(hd.width, hd.height, 1);
uint8_t *dst = res->pix();
uint8_t *src = tmp;
uint8_t lastMask = (1 << (hd.width & 7)) - 1;
uint8_t lastMask = 0xff << (8 - (hd.width & 7));
if (lastMask == 0)
lastMask = 0xff;
for (uint32_t i = 0; i < hd.height; ++i) {
@ -117,7 +109,7 @@ Image unpackPNG(Buffer png) {
return NULL;
}
for (uint32_t j = 0; j < byteW; ++j) {
*dst = ~revbits(*src++);
*dst = ~*src++;
if (j == byteW - 1) {
*dst &= lastMask;
}

View File

@ -32,7 +32,6 @@ class MMap : public RefObject {
extern volatile bool paniced;
// Buffer, Sound, and Image share representation.
typedef Buffer Image;
typedef Buffer Sound;
}
@ -41,4 +40,6 @@ typedef Buffer Sound;
#define DEVICE_ID_NOTIFY 10000
#define DEVICE_ID_NOTIFY_ONE 10001
#define IMAGE_BITS 1
#endif

View File

@ -16,7 +16,6 @@
"buttons.ts",
"png.cpp",
"screen.cpp",
"screen.ts",
"battery.ts",
"output.cpp",
"output.ts",
@ -26,8 +25,6 @@
"shims.d.ts",
"enums.d.ts",
"dal.d.ts",
"images.ts",
"images.jres",
"icons.jres",
"ns.ts"
],

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

View File

@ -1,214 +0,0 @@
namespace brick {
export const LINE_HEIGHT = 12;
//% shim=screen::_setPixel
function _setPixel(p0: uint32, p1: uint32, mode: Draw): void { }
//% shim=screen::_blitLine
function _blitLine(xw: uint32, y: uint32, buf: Buffer, mode: Draw): void { }
function pack(x: number, y: number) {
return Math.clamp(0, 512, x) | (Math.clamp(0, 512, y) << 16)
}
const ones = hex`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
function setLineCore(x: number, x1: number, y: number, mode: Draw) {
_blitLine(pack(x, x1 - x), y, ones, mode)
}
export interface Font {
charWidth: number;
charHeight: number;
firstChar: number;
data: Buffer;
}
let currFont: Font
export function setFont(f: Font) {
currFont = f
}
export const heart = screen.imageOf(hex`f007 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
`
}
}
function setPixel(on: boolean, x: number, y: number) {
x |= 0
y |= 0
if (0 <= x && x < DAL.LCD_WIDTH && 0 <= y && y < DAL.LCD_HEIGHT)
_setPixel(x, y, on ? Draw.Normal : Draw.Clear)
}
/**
* Show text on the screen at a specific line.
* @param text the text to print on the screen, eg: "Hello world"
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screen_print block="show string %text|at line %line"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-string
//% line.min=1 line.max=10
export function showString(text: string, line: number) {
const NUM_LINES = 9;
const offset = 5;
const y = offset + (Math.clamp(0, NUM_LINES, line - 1) / (NUM_LINES + 2)) * DAL.LCD_HEIGHT;
brick.print(text, offset, y);
}
/**
* Shows a number on the screen
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screenShowNumber block="show number %name|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-number
//% line.min=1 line.max=10
export function showNumber(value: number, line: number) {
showString("" + value, line);
}
/**
* Shows a name, value pair on the screen
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screenShowValue block="show value %name|= %text|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-value
//% line.min=1 line.max=10
export function showValue(name: string, value: number, line: number) {
value = Math.round(value * 1000) / 1000;
showString((name ? name + ": " : "") + value, line);
}
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
x |= 0
y |= 0
if (!currFont) currFont = defaultFont()
let x0 = x
let cp = 0
let byteWidth = (currFont.charWidth + 7) >> 3
let charSize = byteWidth * currFont.charHeight
let imgBuf = output.createBuffer(2 + charSize)
let double = (mode & Draw.Quad) ? 4 : (mode & Draw.Double) ? 2 : 1
imgBuf[0] = 0xf0
imgBuf[1] = currFont.charWidth
let img = screen.imageOf(imgBuf)
while (cp < text.length) {
let ch = text.charCodeAt(cp++)
if (ch == 10) {
y += double * currFont.charHeight + 2
x = x0
}
if (ch < 32) continue
let idx = (ch - currFont.firstChar) * charSize
if (idx < 0 || idx + imgBuf.length - 1 > currFont.data.length)
imgBuf.fill(0, 2)
else
imgBuf.write(2, currFont.data.slice(idx, charSize))
img.draw(x, y, mode)
x += double * currFont.charWidth
}
}
/**
* Show an image on the screen
* @param image image to draw
*/
//% blockId=screen_show_image block="show image %image=screen_image_picker"
//% weight=100 group="Screen" blockGap=8
//% help=brick/show-image
export function showImage(image: Image) {
if (!image) return;
image.draw(0, 0, Draw.Normal);
}
/**
* An image
* @param image the image
*/
//% blockId=screen_image_picker block="%image" shim=TD_ID
//% image.fieldEditor="images"
//% image.fieldOptions.columns=6
//% image.fieldOptions.width=600
//% group="Screen" weight=0 blockHidden=1
export function __imagePicker(image: Image): Image {
return image;
}
/**
* Clear the screen
*/
//% blockId=screen_clear_screen block="clear screen"
//% weight=90 group="Screen"
//% help=brick/clear-screen
export function clearScreen() {
screen.clear();
}
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(DAL.LCD_WIDTH, x + w);
let y1 = Math.min(DAL.LCD_HEIGHT, y + h);
if (w == 1) {
while (y < y1)
_setPixel(x, y++, mode);
return;
}
setLineCore(x, x1, y++, mode);
while (y < y1 - 1) {
if (mode & Draw.Fill) {
setLineCore(x, x1, y, mode);
} else {
_setPixel(x, y, mode);
_setPixel(x1 - 1, y, mode);
}
y++;
}
if (y < y1)
setLineCore(x, x1, y, mode);
}
}

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

@ -75,47 +75,12 @@ declare namespace serial {
//% shim=serial::writeDmesg
function writeDmesg(): void;
}
declare namespace screen {
declare namespace image {
/** Decompresses a 1-bit gray scale PNG image to image format. */
//% shim=screen::unpackPNG
//% shim=image::unpackPNG
function unpackPNG(png: Buffer): Image;
}
declare namespace screen {
/** Clear screen and reset font to normal. */
//% shim=screen::clear
function clear(): void;
/** Makes an image bound to a buffer. */
//% shim=screen::imageOf
function imageOf(buf: Buffer): Image;
}
//% fixedInstances
declare interface Image {
/** Returns the underlaying Buffer object. */
//% property shim=ImageMethods::buffer
buffer: Buffer;
/** Returns the width of an image. */
//% property shim=ImageMethods::width
width: int32;
/** Returns the height of an image. */
//% property shim=ImageMethods::height
height: int32;
/** Double size of an image. */
//% shim=ImageMethods::doubled
doubled(): Image;
/** Draw an image on the screen. */
//% shim=ImageMethods::draw
draw(x: int32, y: int32, mode: Draw): void;
}
declare namespace output {
/**

View File

@ -1,229 +1,229 @@
namespace images {
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsBigSmile = screen.unpackPNG(hex``);
export const expressionsBigSmile = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsHeartLarge = screen.unpackPNG(hex``);
export const expressionsHeartLarge = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsHeartSmall = screen.unpackPNG(hex``);
export const expressionsHeartSmall = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth1open = screen.unpackPNG(hex``);
export const expressionsMouth1open = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth1shut = screen.unpackPNG(hex``);
export const expressionsMouth1shut = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth2open = screen.unpackPNG(hex``);
export const expressionsMouth2open = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth2shut = screen.unpackPNG(hex``);
export const expressionsMouth2shut = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSad = screen.unpackPNG(hex``);
export const expressionsSad = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSick = screen.unpackPNG(hex``);
export const expressionsSick = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSmile = screen.unpackPNG(hex``);
export const expressionsSmile = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSwearing = screen.unpackPNG(hex``);
export const expressionsSwearing = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsTalking = screen.unpackPNG(hex``);
export const expressionsTalking = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsWink = screen.unpackPNG(hex``);
export const expressionsWink = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsZzz = screen.unpackPNG(hex``);
export const expressionsZzz = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesAngry = screen.unpackPNG(hex``);
export const eyesAngry = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesAwake = screen.unpackPNG(hex``);
export const eyesAwake = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBlackEye = screen.unpackPNG(hex``);
export const eyesBlackEye = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBottomLeft = screen.unpackPNG(hex``);
export const eyesBottomLeft = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBottomRight = screen.unpackPNG(hex``);
export const eyesBottomRight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesCrazy1 = screen.unpackPNG(hex``);
export const eyesCrazy1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesCrazy2 = screen.unpackPNG(hex``);
export const eyesCrazy2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDisappointed = screen.unpackPNG(hex``);
export const eyesDisappointed = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDizzy = screen.unpackPNG(hex``);
export const eyesDizzy = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDown = screen.unpackPNG(hex``);
export const eyesDown = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesEvil = screen.unpackPNG(hex``);
export const eyesEvil = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesHurt = screen.unpackPNG(hex``);
export const eyesHurt = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesKnockedOut = screen.unpackPNG(hex``);
export const eyesKnockedOut = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesLove = screen.unpackPNG(hex``);
export const eyesLove = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesMiddleLeft = screen.unpackPNG(hex``);
export const eyesMiddleLeft = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesMiddleRight = screen.unpackPNG(hex``);
export const eyesMiddleRight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesNeutral = screen.unpackPNG(hex``);
export const eyesNeutral = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesNuclear = screen.unpackPNG(hex``);
export const eyesNuclear = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchLeft = screen.unpackPNG(hex``);
export const eyesPinchLeft = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchMiddle = screen.unpackPNG(hex``);
export const eyesPinchMiddle = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchRight = screen.unpackPNG(hex``);
export const eyesPinchRight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesSleeping = screen.unpackPNG(hex``);
export const eyesSleeping = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTear = screen.unpackPNG(hex``);
export const eyesTear = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredLeft = screen.unpackPNG(hex``);
export const eyesTiredLeft = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredMiddle = screen.unpackPNG(hex``);
export const eyesTiredMiddle = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredRight = screen.unpackPNG(hex``);
export const eyesTiredRight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesToxic = screen.unpackPNG(hex``);
export const eyesToxic = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesUp = screen.unpackPNG(hex``);
export const eyesUp = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesWinking = screen.unpackPNG(hex``);
export const eyesWinking = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationAccept = screen.unpackPNG(hex``);
export const informationAccept = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationBackward = screen.unpackPNG(hex``);
export const informationBackward = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationDecline = screen.unpackPNG(hex``);
export const informationDecline = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationForward = screen.unpackPNG(hex``);
export const informationForward = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationLeft = screen.unpackPNG(hex``);
export const informationLeft = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationNoGo = screen.unpackPNG(hex``);
export const informationNoGo = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationQuestionMark = screen.unpackPNG(hex``);
export const informationQuestionMark = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationRight = screen.unpackPNG(hex``);
export const informationRight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationStop1 = screen.unpackPNG(hex``);
export const informationStop1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationStop2 = screen.unpackPNG(hex``);
export const informationStop2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationThumbsDown = screen.unpackPNG(hex``);
export const informationThumbsDown = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationThumbsUp = screen.unpackPNG(hex``);
export const informationThumbsUp = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationWarning = screen.unpackPNG(hex``);
export const informationWarning = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoColorSensor = screen.unpackPNG(hex``);
export const legoColorSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoEv3icon = screen.unpackPNG(hex``);
export const legoEv3icon = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoEv3 = screen.unpackPNG(hex``);
export const legoEv3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoGyroSensor = screen.unpackPNG(hex``);
export const legoGyroSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoIrBeacon = screen.unpackPNG(hex``);
export const legoIrBeacon = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoIrSensor = screen.unpackPNG(hex``);
export const legoIrSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoLego = screen.unpackPNG(hex``);
export const legoLego = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoLargeMotor = screen.unpackPNG(hex``);
export const legoLargeMotor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoMindstorms = screen.unpackPNG(hex``);
export const legoMindstorms = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoMediumMotor = screen.unpackPNG(hex``);
export const legoMediumMotor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoSoundSensor = screen.unpackPNG(hex``);
export const legoSoundSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoTempSensor = screen.unpackPNG(hex``);
export const legoTempSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoTouchSensor = screen.unpackPNG(hex``);
export const legoTouchSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoUsSensor = screen.unpackPNG(hex``);
export const legoUsSensor = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsBomb = screen.unpackPNG(hex``);
export const objectsBomb = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsBoom = screen.unpackPNG(hex``);
export const objectsBoom = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsFire = screen.unpackPNG(hex``);
export const objectsFire = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsFlowers = screen.unpackPNG(hex``);
export const objectsFlowers = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsForest = screen.unpackPNG(hex``);
export const objectsForest = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightOff = screen.unpackPNG(hex``);
export const objectsLightOff = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightOn = screen.unpackPNG(hex``);
export const objectsLightOn = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightning = screen.unpackPNG(hex``);
export const objectsLightning = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsNight = screen.unpackPNG(hex``);
export const objectsNight = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsPirate = screen.unpackPNG(hex``);
export const objectsPirate = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsSnow = screen.unpackPNG(hex``);
export const objectsSnow = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsTarget = screen.unpackPNG(hex``);
export const objectsTarget = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar0 = screen.unpackPNG(hex``);
export const progressBar0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar1 = screen.unpackPNG(hex``);
export const progressBar1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar2 = screen.unpackPNG(hex``);
export const progressBar2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar3 = screen.unpackPNG(hex``);
export const progressBar3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar4 = screen.unpackPNG(hex``);
export const progressBar4 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial0 = screen.unpackPNG(hex``);
export const progressDial0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial1 = screen.unpackPNG(hex``);
export const progressDial1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial2 = screen.unpackPNG(hex``);
export const progressDial2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial3 = screen.unpackPNG(hex``);
export const progressDial3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial4 = screen.unpackPNG(hex``);
export const progressDial4 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots0 = screen.unpackPNG(hex``);
export const progressDots0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots1 = screen.unpackPNG(hex``);
export const progressDots1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots2 = screen.unpackPNG(hex``);
export const progressDots2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots3 = screen.unpackPNG(hex``);
export const progressDots3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass0 = screen.unpackPNG(hex``);
export const progressHourglass0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass1 = screen.unpackPNG(hex``);
export const progressHourglass1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass2 = screen.unpackPNG(hex``);
export const progressHourglass2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer0 = screen.unpackPNG(hex``);
export const progressTimer0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer1 = screen.unpackPNG(hex``);
export const progressTimer1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer2 = screen.unpackPNG(hex``);
export const progressTimer2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer3 = screen.unpackPNG(hex``);
export const progressTimer3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer4 = screen.unpackPNG(hex``);
export const progressTimer4 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel0 = screen.unpackPNG(hex``);
export const progressWaterLevel0 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel1 = screen.unpackPNG(hex``);
export const progressWaterLevel1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel2 = screen.unpackPNG(hex``);
export const progressWaterLevel2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel3 = screen.unpackPNG(hex``);
export const progressWaterLevel3 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemAccept1 = screen.unpackPNG(hex``);
export const systemAccept1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemAccept2 = screen.unpackPNG(hex``);
export const systemAccept2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemBox = screen.unpackPNG(hex``);
export const systemBox = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDecline1 = screen.unpackPNG(hex``);
export const systemDecline1 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDecline2 = screen.unpackPNG(hex``);
export const systemDecline2 = image.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick.__imagePicker
}

View File

@ -4,11 +4,14 @@
"files": [
"README.md",
"ns.ts",
"startup.ts"
"startup.ts",
"images.jres",
"images.ts"
],
"dependencies": {
"base": "file:../base",
"core": "file:../core",
"screen": "file:../screen",
"music": "file:../music",
"color-sensor": "file:../color-sensor",
"touch-sensor": "file:../touch-sensor",

3
libs/game/pxt.json Normal file
View File

@ -0,0 +1,3 @@
{
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/game"
}

3
libs/screen/pxt.json Normal file
View File

@ -0,0 +1,3 @@
{
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/screen"
}

128
libs/screen/shims.d.ts vendored Normal file
View File

@ -0,0 +1,128 @@
// Auto-generated. Do not edit.
declare interface Image {
/**
* Get the width of the image
*/
//% property shim=ImageMethods::width
width: int32;
/**
* Get the height of the image
*/
//% property shim=ImageMethods::height
height: int32;
/**
* True iff the image is monochromatic (black and white)
*/
//% property shim=ImageMethods::isMono
isMono: boolean;
/**
* Set pixel color
*/
//% shim=ImageMethods::set
set(x: int32, y: int32, c: int32): void;
/**
* Get a pixel color
*/
//% shim=ImageMethods::get
get(x: int32, y: int32): int32;
/**
* Fill entire image with a given color
*/
//% shim=ImageMethods::fill
fill(c: int32): void;
/**
* Return a copy of the current image
*/
//% shim=ImageMethods::clone
clone(): Image;
/**
* Flips (mirrors) pixels horizontally in the current image
*/
//% shim=ImageMethods::flipX
flipX(): void;
/**
* Flips (mirrors) pixels vertically in the current image
*/
//% shim=ImageMethods::flipY
flipY(): void;
/**
* Every pixel in image is moved by (dx,dy)
*/
//% shim=ImageMethods::scroll
scroll(dx: int32, dy: int32): void;
/**
* Stretches the image horizontally by 100%
*/
//% shim=ImageMethods::doubledX
doubledX(): Image;
/**
* Stretches the image vertically by 100%
*/
//% shim=ImageMethods::doubledY
doubledY(): Image;
/**
* Replaces one color in an image with another
*/
//% shim=ImageMethods::replace
replace(from: int32, to: int32): void;
/**
* Stretches the image in both directions by 100%
*/
//% shim=ImageMethods::doubled
doubled(): Image;
/**
* Draw given image on the current image
*/
//% shim=ImageMethods::drawImage
drawImage(from: Image, x: int32, y: int32): void;
/**
* Draw given image with transparent background on the current image
*/
//% shim=ImageMethods::drawTransparentImage
drawTransparentImage(from: Image, x: int32, y: int32): void;
/**
* Check if the current image "collides" with another
*/
//% shim=ImageMethods::overlapsWith
overlapsWith(other: Image, x: int32, y: int32): boolean;
}
declare namespace image {
/**
* Create new empty (transparent) image
*/
//% shim=image::create
function create(width: int32, height: int32): Image;
/**
* Create new image with given content
*/
//% shim=image::ofBuffer
function ofBuffer(buf: Buffer): Image;
/**
* Double the size of an icon
*/
//% shim=image::doubledIcon
function doubledIcon(icon: Buffer): Buffer;
}
// Auto-generated. Do not edit. Really.

View File

@ -0,0 +1,107 @@
/**
* Tagged image literal converter
*/
//% shim=@f4 helper=image::ofBuffer
//% groups=["0.,","1#*"]
function img(lits: any, ...args: any[]): Image { return null }
let screen = image.create(DAL.LCD_WIDTH, DAL.LCD_HEIGHT)
namespace _screen_internal {
//% shim=pxt::updateScreen
function updateScreen(img: Image): void {}
control.addFrameHandler(200, () => {
updateScreen(screen)
})
updateScreen(screen)
export function _stats(msg: string) {
// show the msg somewhere - it contains frame rate etc
}
}
namespace brick {
export const LINE_HEIGHT = 12;
/**
* Show text on the screen at a specific line.
* @param text the text to print on the screen, eg: "Hello world"
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screen_print block="show string %text|at line %line"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-string
//% line.min=1 line.max=10
export function showString(text: string, line: number) {
const NUM_LINES = 9;
const offset = 5;
const y = offset + (Math.clamp(0, NUM_LINES, line - 1) / (NUM_LINES + 2)) * DAL.LCD_HEIGHT;
screen.print(text, offset, y);
}
/**
* Shows a number on the screen
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screenShowNumber block="show number %name|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-number
//% line.min=1 line.max=10
export function showNumber(value: number, line: number) {
showString("" + value, line);
}
/**
* Shows a name, value pair on the screen
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screenShowValue block="show value %name|= %text|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-value
//% line.min=1 line.max=10
export function showValue(name: string, value: number, line: number) {
value = Math.round(value * 1000) / 1000;
showString((name ? name + ": " : "") + value, line);
}
/**
* Show an image on the screen
* @param image image to draw
*/
//% blockId=screen_show_image block="show image %image=screen_image_picker"
//% weight=100 group="Screen" blockGap=8
//% help=brick/show-image
export function showImage(image: Image) {
if (!image) return;
screen.drawImage(image, 0, 0)
}
/**
* An image
* @param image the image
*/
//% blockId=screen_image_picker block="%image" shim=TD_ID
//% image.fieldEditor="images"
//% image.fieldOptions.columns=6
//% image.fieldOptions.width=600
//% group="Screen" weight=0 blockHidden=1
export function __imagePicker(image: Image): Image {
return image;
}
/**
* Clear the screen
*/
//% blockId=screen_clear_screen block="clear screen"
//% weight=90 group="Screen"
//% help=brick/clear-screen
export function clearScreen() {
screen.fill(0)
}
}

View File

@ -21,6 +21,8 @@
"libs/storage",
"libs/datalog",
"libs/tests",
"libs/screen",
"libs/game",
"libs/automation"
],
"simulator": {

View File

@ -11,7 +11,7 @@ namespace pxsim {
analogState: EV3AnalogState;
uartState: EV3UArtState;
motorState: EV3MotorState;
screenState: EV3ScreenState;
screenState: ScreenState;
audioState: AudioState;
remoteState: RemoteState;
@ -37,7 +37,7 @@ namespace pxsim {
this.analogState = new EV3AnalogState();
this.uartState = new EV3UArtState();
this.motorState = new EV3MotorState();
this.screenState = new EV3ScreenState();
this.screenState = new ScreenState(["#97b5a6", "#000000"], visuals.SCREEN_WIDTH, visuals.SCREEN_HEIGHT);
this.audioState = new AudioState();
this.remoteState = new RemoteState();
}

View File

@ -1,134 +1,8 @@
namespace pxsim {
function OFF(x: number, y: number) {
return x + y * visuals.SCREEN_WIDTH
}
export class EV3ScreenState {
changed: boolean = true;
points: Uint8Array;
constructor() {
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
}
applyMode(off: number, v: number) {
if (v & Draw.Clear)
this.points[off] = 0;
else if (v & Draw.Xor)
this.points[off] = this.points[off] ? 0 : 255;
else
this.points[off] = 255;
}
setPixel(x: number, y: number, v: number) {
this.applyMode(OFF(x, y), v)
this.changed = true;
}
clear() {
for (let i = 0; i < this.points.length; ++i)
this.points[i] = 0;
this.changed = true;
}
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
if (y < 0 || y >= visuals.SCREEN_HEIGHT)
return;
if (x + w <= 0)
return;
if (x >= visuals.SCREEN_WIDTH)
return;
let off = OFF(x, y);
const off0 = OFF(0, y);
const off1 = OFF(visuals.SCREEN_WIDTH - 1, y);
let mask = 0x01
let dp = offset
for (let i = 0; i < w; ++i) {
if ((buf.data[dp] & mask) && off0 <= off && off <= off1) {
this.applyMode(off, mode);
}
off++
mask <<= 1
if (mask & 0x100) {
mask = 0x01
dp++
}
}
this.changed = true;
}
clearLine(x: number, y: number, w: number) {
let off = OFF(x, y);
const off0 = OFF(0, y);
const off1 = OFF(visuals.SCREEN_WIDTH - 1, y);
for (let i = 0; i < w; ++i) {
if (off0 <= off && off <= off1) {
this.points[off] = 0
}
off++
}
}
didChange() {
const res = this.changed;
this.changed = false;
return res;
}
}
}
namespace pxsim.screen {
function XX(v: number) { return (v << 16) >> 16 }
function YY(v: number) { return v >> 16 }
export function _setPixel(x: number, y: number, mode: Draw) {
const screenState = ev3board().screenState;
screenState.setPixel(x, y, mode);
}
export function _blitLine(xw: number, y: number, buf: RefBuffer, mode: Draw) {
const screenState = ev3board().screenState;
screenState.blitLineCore(XX(xw), y, YY(xw), buf, mode)
}
export function isValidImage(buf: RefBuffer) {
return buf.data.length >= 3 && buf.data[0] == 0xf0;
}
export function PIX2BYTES(x: number) {
return ((x + 7) >> 3)
}
export function clear(): void {
const screenState = ev3board().screenState;
screenState.clear()
}
export function dump() {
// No need for this one.
}
export function imageOf(buf: RefBuffer) {
return incr(buf)
}
}
namespace pxsim.screen {
namespace pxsim.image {
function DMESG(msg: string) {
control.dmesg(msg)
}
const NULL: RefBuffer = null;
function revbits(v: number) {
v = (v & 0xf0) >> 4 | (v & 0x0f) << 4;
v = (v & 0xcc) >> 2 | (v & 0x33) << 2;
v = (v & 0xaa) >> 1 | (v & 0x55) << 1;
return v;
}
export function unpackPNG(png: RefBuffer) {
function memcmp(off: number, mark: string) {
@ -198,10 +72,11 @@ namespace pxsim.screen {
return NULL;
}
const res = output.createBuffer(2 + byteW * height);
res.data[0] = 0xf0;
const res = output.createBuffer(3 + byteW * height);
res.data[0] = 0xf1;
res.data[1] = width;
let dst = 2
res.data[2] = height;
let dst = 3
let src = 0
let lastMask = (1 << (width & 7)) - 1;
if (lastMask == 0)
@ -213,99 +88,13 @@ namespace pxsim.screen {
return NULL;
}
for (let j = 0; j < byteW; ++j) {
res.data[dst] = ~revbits(two[src++]);
res.data[dst] = ~(two[src++]);
if (j == byteW - 1) {
res.data[dst] &= lastMask;
}
dst++;
}
}
return res;
return image.ofBuffer(res)
}
}
namespace pxsim.ImageMethods {
const bitdouble = [
0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
]
export function buffer(buf: RefBuffer) {
return incr(buf)
}
export function width(buf: RefBuffer) {
if (!screen.isValidImage(buf)) return 0
return buf.data[1]
}
export function height(buf: RefBuffer) {
if (!screen.isValidImage(buf)) return 0
const bw = screen.PIX2BYTES(buf.data[1]);
const h = ((buf.data.length - 2) / bw) | 0;
return h
}
export function draw(buf: RefBuffer, x: number, y: number, mode: Draw): void {
const screenState = ev3board().screenState;
if (!screen.isValidImage(buf))
return;
if (mode & (Draw.Double | Draw.Quad)) {
buf = doubled(buf);
if (mode & Draw.Quad) {
let pbuf = buf;
buf = doubled(buf);
decr(pbuf);
}
}
let pixwidth = buf.data[1];
let ptr = 2;
const bytewidth = screen.PIX2BYTES(pixwidth);
pixwidth = Math.min(pixwidth, visuals.SCREEN_WIDTH);
while (ptr + bytewidth <= buf.data.length) {
if (mode & (Draw.Clear | Draw.Xor | Draw.Transparent)) {
// no erase of background
} else {
screenState.clearLine(x, y, pixwidth)
}
screenState.blitLineCore(x, y, pixwidth, buf, mode, ptr);
y++;
ptr += bytewidth;
}
if (mode & (Draw.Double | Draw.Quad))
decr(buf);
}
export function doubled(buf: RefBuffer): RefBuffer {
if (!screen.isValidImage(buf))
return null;
const w = buf.data[1];
if (w > 126)
return null;
const bw = screen.PIX2BYTES(w);
const h = ((buf.data.length - 2) / bw) | 0;
const bw2 = screen.PIX2BYTES(w * 2);
const out = pins.createBuffer(2 + bw2 * h * 2)
out.data[0] = 0xf0;
out.data[1] = w * 2;
let src = 2
let dst = 2
for (let i = 0; i < h; ++i) {
for (let jj = 0; jj < 2; ++jj) {
let p = src;
for (let j = 0; j < bw; ++j) {
const v = buf.data[p++]
out.data[dst++] = bitdouble[v & 0xf];
out.data[dst++] = bitdouble[v >> 4];
}
}
src += bw;
}
return out;
}
}

View File

@ -500,7 +500,7 @@ namespace pxsim.visuals {
}
}
private updateScreenStep(state: EV3ScreenState) {
private updateScreenStep(state: ScreenState) {
const bBox = this.layoutView.getBrick().getScreenBBox();
if (!bBox || bBox.width == 0) return;
@ -515,13 +515,7 @@ namespace pxsim.visuals {
this.screenCanvasData = this.screenCanvasCtx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
let sp = 3
const points = state.points
const data = this.screenCanvasData.data
for (let i = 0; i < points.length; ++i) {
data[sp] = points[i]
sp += 4;
}
new Uint32Array(this.screenCanvasData.data.buffer).set(state.screen)
// Move the image to another canvas element in order to scale it
this.screenCanvasTemp.style.width = `${SCREEN_WIDTH}`;