2017-12-12 20:41:32 +01:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Basic matrix driver which every implementation can derive from
|
|
|
|
*/
|
|
|
|
class Driver {
|
|
|
|
constructor() {
|
|
|
|
|
|
|
|
// Some sane-ish defaults
|
|
|
|
this.setSize( 16, 16 );
|
|
|
|
this.setBrightness( 1 );
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
this.flipHorizontal = false;
|
|
|
|
this.flipVertical = false;
|
|
|
|
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the display size
|
|
|
|
*/
|
|
|
|
setSize( w, h ) {
|
|
|
|
this.width = w;
|
|
|
|
this.height = h;
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
this.clearMatrix();
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return an object containing the width and height
|
|
|
|
*/
|
|
|
|
getSize() {
|
|
|
|
return {
|
|
|
|
width: this.width,
|
|
|
|
height: this.height
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets brightness between 0.0f and 1.0f
|
|
|
|
*/
|
|
|
|
setBrightness( v ) {
|
|
|
|
this.brightness = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the current brightness
|
|
|
|
*/
|
|
|
|
getBrightness() {
|
|
|
|
return this.brightness;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CLear the matrix with the following color, from 0..255
|
|
|
|
*/
|
2017-12-28 01:03:01 +01:00
|
|
|
clear( r = 0, g = 0, b = 0, a = 1 ) {
|
2017-12-12 20:41:32 +01:00
|
|
|
for ( let x = 0; x < this.width; x++ ) {
|
|
|
|
for ( let y = 0; y < this.height; y++) {
|
2018-01-05 00:03:37 +01:00
|
|
|
this.setPikel( x, y, r, g, b, a );
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set pixel color
|
|
|
|
*/
|
2017-12-28 01:03:01 +01:00
|
|
|
setPixel( x, y, r = 0, g = 0, b = 0, a = 1 ) {
|
2018-01-04 02:36:13 +01:00
|
|
|
if ( x >= 0 && x <= this.width &&
|
|
|
|
y >= 0 && y <= this.height ) {
|
|
|
|
this.matrix[x][y].r = r;
|
|
|
|
this.matrix[x][y].g = g;
|
|
|
|
this.matrix[x][y].b = b;
|
|
|
|
this.matrix[x][y].a = a;
|
|
|
|
}
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the pixel color
|
|
|
|
*/
|
|
|
|
getPixel( x, y ) {
|
2018-01-04 02:36:13 +01:00
|
|
|
if ( x >= 0 && x <= this.width &&
|
|
|
|
y >= 0 && y <= this.height ) {
|
|
|
|
return {
|
|
|
|
r: this.matrix[x][y].r,
|
|
|
|
g: this.matrix[x][y].g,
|
|
|
|
b: this.matrix[x][y].b,
|
|
|
|
a: this.matrix[x][y].a
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:41:32 +01:00
|
|
|
return {
|
2018-01-04 02:36:13 +01:00
|
|
|
r: -1,
|
|
|
|
g: -1,
|
|
|
|
b: -1,
|
|
|
|
a: -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a line from x1,y1 to x2,y2
|
|
|
|
*/
|
|
|
|
drawLine( x1, y1, x2, y2, r = 0, g = 0, b = 0, a = 1 ) {
|
|
|
|
let dx = x2 - x1;
|
|
|
|
let dy = y2 - y1;
|
|
|
|
|
|
|
|
for ( let x = x1; x <= x2; x++ ) {
|
|
|
|
let y = Math.floor( y1 + dy * ( x - x1 ) / dx );
|
|
|
|
|
|
|
|
this.setPixel( x, y, r, g, b, a );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a rectangle from x,y with dimensions w,h
|
|
|
|
*/
|
|
|
|
drawRect( x1, y1, w, h, r = 0, g = 0, b = 0, a = 1 ) {
|
|
|
|
for ( let x = x1; x < x1 + w; x++ ) {
|
|
|
|
this.setPixel( x, y1, r, g, b, a );
|
|
|
|
this.setPixel( x, y1 + h - 1, r, g, b, a );
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( let y = y1; y < y1 + h - 1; y++ ) {
|
|
|
|
this.setPixel( x1, y, r, g, b, a );
|
|
|
|
this.setPixel( x1 + w - 1, y, r, g, b, a );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a rectangle from x,y with dimensions w,h
|
|
|
|
*/
|
|
|
|
drawRectFilled( x1, y1, w, h, r = 0, g = 0, b = 0, a = 1 ) {
|
|
|
|
for ( let x = x1; x < x1 + w; x++ ) {
|
|
|
|
for ( let y = y1; y < y1 + h; y++ ) {
|
|
|
|
this.setPixel( x, y, r, g, b, a );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws a circle at x,y with radius r
|
|
|
|
*/
|
|
|
|
drawCircle( x1, y1, radius, r = 0, g = 0, b = 0, a = 1 ) {
|
|
|
|
let x = radius - 1;
|
|
|
|
let y = 0;
|
|
|
|
let dx = 1;
|
|
|
|
let dy = 1;
|
|
|
|
let err = dx - ( radius << 1 );
|
|
|
|
|
|
|
|
while ( x >= y ) {
|
|
|
|
this.setPixel( x1 + x, y1 + y, r, g, b, a );
|
|
|
|
this.setPixel( x1 + y, y1 + x, r, g, b, a );
|
|
|
|
this.setPixel( x1 - y, y1 + x, r, g, b, a );
|
|
|
|
this.setPixel( x1 - x, y1 + y, r, g, b, a );
|
|
|
|
this.setPixel( x1 - x, y1 - y, r, g, b, a );
|
|
|
|
this.setPixel( x1 - y, y1 - x, r, g, b, a );
|
|
|
|
this.setPixel( x1 + y, y1 - x, r, g, b, a );
|
|
|
|
this.setPixel( x1 + x, y1 - y, r, g, b, a );
|
|
|
|
|
|
|
|
if ( err <= 0 ) {
|
|
|
|
y++;
|
|
|
|
err += dy;
|
|
|
|
dy += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( err > 0 ) {
|
|
|
|
x--;
|
|
|
|
dx += 2;
|
|
|
|
err += dx - ( radius << 1 );
|
|
|
|
}
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the buffer for writing
|
|
|
|
* @return {Buffer}
|
|
|
|
*/
|
|
|
|
getBuffer() {
|
2017-12-18 20:39:51 +01:00
|
|
|
this.flipMatrix( this.flipHorizontal, this.flipVertical );
|
|
|
|
|
2017-12-12 20:41:32 +01:00
|
|
|
let buffer = new Buffer( this.width * this.height * 3 );
|
|
|
|
|
|
|
|
let size = this.getSize();
|
|
|
|
|
|
|
|
// @TODO: for now this only supports square displays!
|
|
|
|
for ( let y = 0; y < size.height; y++ ) {
|
|
|
|
for ( let x = 0; x < size.width; x++ ) {
|
2017-12-28 01:03:01 +01:00
|
|
|
buffer[ y * size.height * 3 + x * 3 + 0 ] = this.matrix[ x ][ y ].r * this.matrix[ x ][ y ].a * this.brightness;
|
|
|
|
buffer[ y * size.height * 3 + x * 3 + 1 ] = this.matrix[ x ][ y ].g * this.matrix[ x ][ y ].a * this.brightness;
|
|
|
|
buffer[ y * size.height * 3 + x * 3 + 2 ] = this.matrix[ x ][ y ].b * this.matrix[ x ][ y ].a * this.brightness;
|
2017-12-12 20:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
/**
|
|
|
|
* Write output to the device. Implement at driver level.
|
|
|
|
*/
|
2017-12-12 20:41:32 +01:00
|
|
|
write( buffer ) {
|
|
|
|
console.log( 'Driver should implement this' );
|
|
|
|
}
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
/**
|
|
|
|
* Flip the matrix along it's axis.
|
|
|
|
*/
|
|
|
|
flipMatrix( horizontal, vertical ) {
|
|
|
|
if ( horizontal === true ) {
|
|
|
|
for ( let i = 0; i < this.matrix.length; i++ ) {
|
|
|
|
this.matrix[ i ].reverse();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( vertical === true ) {
|
|
|
|
this.matrix.reverse();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:41:32 +01:00
|
|
|
/**
|
|
|
|
* Create the internal frame
|
|
|
|
*/
|
2017-12-18 20:39:51 +01:00
|
|
|
clearMatrix() {
|
2017-12-12 20:41:32 +01:00
|
|
|
this.matrix = [];
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
for ( let y = 0; y < this.height; y++ ) {
|
2017-12-12 20:41:32 +01:00
|
|
|
this.matrix.push( [] );
|
|
|
|
|
2017-12-18 20:39:51 +01:00
|
|
|
for ( let x = 0; x < this.width; x++ ) {
|
2017-12-12 20:41:32 +01:00
|
|
|
this.matrix[ y ].push( {
|
|
|
|
r: 0,
|
|
|
|
g: 0,
|
2017-12-28 01:03:01 +01:00
|
|
|
b: 0,
|
|
|
|
a: 1
|
2017-12-12 20:41:32 +01:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.Driver = Driver;
|