From c2d26a8418a38aad7cc0038fd98e35e6e7e377e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Moskal?= Date: Mon, 26 Feb 2018 23:16:17 +0000 Subject: [PATCH] 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 --- docs/getting-started.md | 6 +- docs/getting-started/try.md | 178 ++++++++++++++++++ docs/getting-started/use.md | 114 ++++++++++++ libs/base/shims.d.ts | 9 + libs/core/console.ts | 6 +- libs/core/enums.d.ts | 15 -- libs/core/png.cpp | 20 +- libs/core/pxt.h | 3 +- libs/core/pxt.json | 3 - libs/core/screen.cpp | 321 +++++---------------------------- libs/core/screen.ts | 214 ---------------------- libs/core/shims.d.ts | 39 +--- libs/{core => ev3}/images.jres | 0 libs/{core => ev3}/images.ts | 226 +++++++++++------------ libs/ev3/pxt.json | 5 +- libs/game/pxt.json | 3 + libs/screen/pxt.json | 3 + libs/screen/shims.d.ts | 128 +++++++++++++ libs/screen/targetoverrides.ts | 107 +++++++++++ pxtarget.json | 2 + sim/dalboard.ts | 4 +- sim/state/screen.ts | 225 +---------------------- sim/visuals/board.ts | 10 +- 23 files changed, 733 insertions(+), 908 deletions(-) create mode 100644 docs/getting-started/try.md create mode 100644 docs/getting-started/use.md delete mode 100644 libs/core/screen.ts rename libs/{core => ev3}/images.jres (100%) rename libs/{core => ev3}/images.ts (51%) create mode 100644 libs/game/pxt.json create mode 100644 libs/screen/pxt.json create mode 100644 libs/screen/shims.d.ts create mode 100644 libs/screen/targetoverrides.ts diff --git a/docs/getting-started.md b/docs/getting-started.md index f17dc414..45134b85 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -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" } diff --git a/docs/getting-started/try.md b/docs/getting-started/try.md new file mode 100644 index 00000000..614525a0 --- /dev/null +++ b/docs/getting-started/try.md @@ -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. + diff --git a/docs/getting-started/use.md b/docs/getting-started/use.md new file mode 100644 index 00000000..8cbb484c --- /dev/null +++ b/docs/getting-started/use.md @@ -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. It’s 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. diff --git a/libs/base/shims.d.ts b/libs/base/shims.d.ts index e89e65fb..913d5e7f 100644 --- a/libs/base/shims.d.ts +++ b/libs/base/shims.d.ts @@ -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 { /** diff --git a/libs/core/console.ts b/libs/core/console.ts index 3e065fbe..6bf1971b 100644 --- a/libs/core/console.ts +++ b/libs/core/console.ts @@ -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) } } diff --git a/libs/core/enums.d.ts b/libs/core/enums.d.ts index 5710758c..eae945cf 100644 --- a/libs/core/enums.d.ts +++ b/libs/core/enums.d.ts @@ -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. diff --git a/libs/core/png.cpp b/libs/core/png.cpp index 9932a6bc..f09f8af9 100644 --- a/libs/core/png.cpp +++ b/libs/core/png.cpp @@ -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; } diff --git a/libs/core/pxt.h b/libs/core/pxt.h index 8bd3b92c..debeff6f 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -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 diff --git a/libs/core/pxt.json b/libs/core/pxt.json index adfb69d5..1ba62acd 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -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" ], diff --git a/libs/core/screen.cpp b/libs/core/screen.cpp index 01e058c6..629c16ac 100644 --- a/libs/core/screen.cpp +++ b/libs/core/screen.cpp @@ -9,39 +9,12 @@ #include #include -/** -* 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); -} -} \ No newline at end of file +} // namespace pxt diff --git a/libs/core/screen.ts b/libs/core/screen.ts deleted file mode 100644 index d257ff8a..00000000 --- a/libs/core/screen.ts +++ /dev/null @@ -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); - } -} \ No newline at end of file diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 13d27854..55b2f2a4 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -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 { /** diff --git a/libs/core/images.jres b/libs/ev3/images.jres similarity index 100% rename from libs/core/images.jres rename to libs/ev3/images.jres diff --git a/libs/core/images.ts b/libs/ev3/images.ts similarity index 51% rename from libs/core/images.ts rename to libs/ev3/images.ts index f51f4608..6d4b67f0 100644 --- a/libs/core/images.ts +++ b/libs/ev3/images.ts @@ -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 } diff --git a/libs/ev3/pxt.json b/libs/ev3/pxt.json index 3ef1c90e..764a9871 100644 --- a/libs/ev3/pxt.json +++ b/libs/ev3/pxt.json @@ -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", diff --git a/libs/game/pxt.json b/libs/game/pxt.json new file mode 100644 index 00000000..e0d15550 --- /dev/null +++ b/libs/game/pxt.json @@ -0,0 +1,3 @@ +{ + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/game" +} diff --git a/libs/screen/pxt.json b/libs/screen/pxt.json new file mode 100644 index 00000000..52498fb3 --- /dev/null +++ b/libs/screen/pxt.json @@ -0,0 +1,3 @@ +{ + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/screen" +} diff --git a/libs/screen/shims.d.ts b/libs/screen/shims.d.ts new file mode 100644 index 00000000..8033f4a4 --- /dev/null +++ b/libs/screen/shims.d.ts @@ -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. diff --git a/libs/screen/targetoverrides.ts b/libs/screen/targetoverrides.ts new file mode 100644 index 00000000..b0dee8cb --- /dev/null +++ b/libs/screen/targetoverrides.ts @@ -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) + } +} \ No newline at end of file diff --git a/pxtarget.json b/pxtarget.json index f2907bb5..7142bc5f 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -21,6 +21,8 @@ "libs/storage", "libs/datalog", "libs/tests", + "libs/screen", + "libs/game", "libs/automation" ], "simulator": { diff --git a/sim/dalboard.ts b/sim/dalboard.ts index ab94c902..e5101a5f 100644 --- a/sim/dalboard.ts +++ b/sim/dalboard.ts @@ -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(); } diff --git a/sim/state/screen.ts b/sim/state/screen.ts index d18f1a52..68235d30 100644 --- a/sim/state/screen.ts +++ b/sim/state/screen.ts @@ -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; - } - - -} diff --git a/sim/visuals/board.ts b/sim/visuals/board.ts index 7fef45ff..29103832 100644 --- a/sim/visuals/board.ts +++ b/sim/visuals/board.ts @@ -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}`;