palette based encoding
This commit is contained in:
Родитель
d55db78e5c
Коммит
c03e80b5ad
59
README.md
59
README.md
|
@ -2,6 +2,65 @@
|
|||
|
||||
A neopixel animation based on bitmaps
|
||||
|
||||
# Animation Sheet
|
||||
|
||||
Creates an animation from a pre-rendered set of frames
|
||||
|
||||
```sig
|
||||
light.animationSheet(null, 50)
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
* ``buffer``, the buffer containing the data (more below)
|
||||
* ``interval``, the time in milliseconds between each frame
|
||||
|
||||
## Buffer format
|
||||
|
||||
The bitmap format should be specified as follows. All values are little endian.
|
||||
|
||||
* magic number ``0x2e0a21``, 4 bytes
|
||||
* palette size, 1 byte (``npalette``)
|
||||
* reserved padding, 1 byte
|
||||
* palette, ``npalette`` x 24bit RGB colors
|
||||
* frames, ``nleds`` x number of frames. A contiguous sequence of palette color indices.
|
||||
|
||||
## Example
|
||||
|
||||
### Generating your own animation
|
||||
|
||||
The following sample generates a buffer and uses it to create the animation.
|
||||
|
||||
```typescript
|
||||
const strip = light.pixels;
|
||||
const nleds = strip.length();
|
||||
const ncolors = 3;
|
||||
const nframes = 10;
|
||||
const sheet = pins.createBuffer(6 + ncolors * 3 + nleds * nframes);
|
||||
const palette = sheet.slice(6, ncolors * 3);
|
||||
const frames = sheet.slice(6 + palette.length);
|
||||
|
||||
// magic number
|
||||
sheet.setNumber(0, NumberFormat.UInt32LE, 0x2e0a21);
|
||||
// palette
|
||||
sheet[4] = ncolors;
|
||||
palette[0] = 0xff; // red
|
||||
palette[4] = 0xff; // green
|
||||
palette[8] = 0xff; // blue
|
||||
// filing up colors
|
||||
let k = 0;
|
||||
for (let i = 0; i < nleds; ++i) {
|
||||
for (let j = 0; j < nframes; ++j) {
|
||||
frames[k++] = i + j % ncolors;
|
||||
}
|
||||
}
|
||||
let anim = light.animationSheet(sheet, 50);
|
||||
|
||||
loops.forever(() => {
|
||||
strip.showAnimation(anim, 10000);
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
69
main.ts
69
main.ts
|
@ -1 +1,70 @@
|
|||
namespace light {
|
||||
/**
|
||||
* Creates a neopixel animation from a raw buffer of colors.
|
||||
*/
|
||||
//% help=reference/light/animation-sheet
|
||||
export function animationSheet(buffer: Buffer, interval: number): NeoPixelAnimation {
|
||||
const animation = new BufferAnimation(buffer, interval);
|
||||
return animation;
|
||||
}
|
||||
|
||||
const AnimationSheetMagicNumber = 0x2e0a21;
|
||||
|
||||
class BufferAnimation extends NeoPixelAnimation {
|
||||
private bitmap: Buffer;
|
||||
private interval: number;
|
||||
private step: number;
|
||||
|
||||
constructor(bitmap: Buffer, interval: number) {
|
||||
super();
|
||||
|
||||
this.bitmap = bitmap;
|
||||
this.interval = Math.max(1, interval);
|
||||
this.step = 0;
|
||||
}
|
||||
|
||||
public showFrame(strip: NeoPixelStrip): void {
|
||||
if (this.start < 0) {
|
||||
this.step = 0;
|
||||
this.start = control.millis();
|
||||
}
|
||||
|
||||
// check magic number
|
||||
if (this.bitmap.getNumber(NumberFormat.UInt32LE, 0) != AnimationSheetMagicNumber)
|
||||
return;
|
||||
|
||||
// npalette
|
||||
const npalette = this.bitmap[4];
|
||||
// extract palette and frames
|
||||
const palette = this.bitmap.slice(6, npalette * 3);
|
||||
const frames = this.bitmap.slice(6 + palette.length);
|
||||
|
||||
const n = strip.length();
|
||||
// the image is written row by row
|
||||
let offset = this.step * n;
|
||||
if (offset + n > frames.length) {
|
||||
// last frame is missing images, reset step
|
||||
this.step = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
const bf = strip.buffered();
|
||||
strip.setBuffered(true);
|
||||
// scan colors starting at offset, lookup color and set in neopixel
|
||||
for (let i = 0; i < n; i++) {
|
||||
const k = i + offset;
|
||||
const ci = frames[k];
|
||||
const c = rgb(palette[ci], palette[ci + 1], palette[ci + 2]);
|
||||
strip.setPixelColor(i, c);
|
||||
}
|
||||
strip.show();
|
||||
strip.setBuffered(bf);
|
||||
|
||||
// sleep
|
||||
loops.pause(this.interval);
|
||||
|
||||
// increment step
|
||||
this.step = this.step % n;
|
||||
}
|
||||
}
|
||||
}
|
3
pxt.json
3
pxt.json
|
@ -4,7 +4,8 @@
|
|||
"description": "A neopixel animation based on bitmaps",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"circuit-playground": "*"
|
||||
"core": "*",
|
||||
"light": "*"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
|
|
28
tests.ts
28
tests.ts
|
@ -1 +1,27 @@
|
|||
// tests go here; this will not be compiled when this package is used as a library
|
||||
const strip = light.pixels;
|
||||
const nleds = strip.length();
|
||||
const ncolors = 3;
|
||||
const nframes = 10;
|
||||
const sheet = pins.createBuffer(6 + ncolors * 3 + nleds * nframes);
|
||||
const palette = sheet.slice(6, ncolors * 3);
|
||||
const frames = sheet.slice(6 + palette.length);
|
||||
|
||||
// magic number
|
||||
sheet.setNumber(0, NumberFormat.UInt32LE, 0x2e0a21);
|
||||
// palette
|
||||
sheet[4] = ncolors;
|
||||
palette[0] = 0xff; // red
|
||||
palette[4] = 0xff; // green
|
||||
palette[8] = 0xff; // blue
|
||||
// filing up colors
|
||||
let k = 0;
|
||||
for (let i = 0; i < nleds; ++i) {
|
||||
for (let j = 0; j < nframes; ++j) {
|
||||
frames[k++] = i + j % ncolors;
|
||||
}
|
||||
}
|
||||
let anim = light.animationSheet(sheet, 50);
|
||||
|
||||
loops.forever(() => {
|
||||
strip.showAnimation(anim, 10000);
|
||||
})
|
Загрузка…
Ссылка в новой задаче