Implement faster Graphics ArrayBuffer fill (affects vector fonts + clear)

This commit is contained in:
Gordon Williams 2014-02-12 13:28:03 +00:00
parent 82dfeb89d0
commit 702ecf8b05
3 changed files with 69 additions and 21 deletions

View File

@ -16,6 +16,8 @@
Upgrade fatfs to R0.10a
Tweak jsinteractive.c to help reduce code size
Finally added Long filename support for FatFS (fix #78)
Epic refactor to remove JsParse (fix #17)
Implement faster Graphics ArrayBuffer fill (affects vector fonts + clear)
1v50 : Fix broken Web IDE caused by change to printing JSON for console.log (part of #206)
Fix bug when trying to stringify {5:5}

View File

@ -15,9 +15,10 @@
#include "lcd_arraybuffer.h"
#include "jsvar.h"
int lcdGetPixelIndex_ArrayBuffer(JsGraphics *gfx, short x, short y) {
// returns the BIT index, so the bottom 3 bits specify the bit in the byte
int lcdGetPixelIndex_ArrayBuffer(JsGraphics *gfx, int x, int y, int pixelCount) {
if (gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG) {
if (y&1) x = gfx->data.width-(1+x);
if (y&1) x = gfx->data.width - (x+pixelCount);
}
if (gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE)
return ((x + (y>>3)*gfx->data.width)<<3) | (y&7);
@ -29,18 +30,18 @@ unsigned int lcdGetPixel_ArrayBuffer(JsGraphics *gfx, short x, short y) {
unsigned int col = 0;
JsVar *buf = jsvObjectGetChild(gfx->graphicsVar, "buffer", 0);
if (buf && jsvIsArrayBuffer(buf)) {
int idx = lcdGetPixelIndex_ArrayBuffer(gfx,x,y);
int idx = lcdGetPixelIndex_ArrayBuffer(gfx,x,y,1);
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, buf, idx>>3 );
if (gfx->data.bpp < 8) {
idx = idx & 7;
int mask = (1<<gfx->data.bpp)-1;
int existing = jsvArrayBufferIteratorGetIntegerValue(&it);
col = (existing>>idx)&mask;
unsigned int mask = (unsigned int)(1<<gfx->data.bpp)-1;
unsigned int existing = (unsigned int)jsvArrayBufferIteratorGetIntegerValue(&it);
col = ((existing>>idx)&mask);
} else {
int i;
for (i=0;i<gfx->data.bpp;i+=8) {
col |= jsvArrayBufferIteratorGetIntegerValue(&it)<<i;
col |= ((unsigned int)jsvArrayBufferIteratorGetIntegerValue(&it)) << i;
jsvArrayBufferIteratorNext(&it);
}
}
@ -49,23 +50,32 @@ unsigned int lcdGetPixel_ArrayBuffer(JsGraphics *gfx, short x, short y) {
return col;
}
void lcdSetPixel_ArrayBuffer(JsGraphics *gfx, short x, short y, unsigned int col) {
// set pixelCount pixels starting at x,y
void lcdSetPixels_ArrayBuffer(JsGraphics *gfx, short x, short y, short pixelCount, unsigned int col) {
JsVar *buf = jsvObjectGetChild(gfx->graphicsVar, "buffer", 0);
if (buf && jsvIsArrayBuffer(buf)) {
int idx = lcdGetPixelIndex_ArrayBuffer(gfx,x,y);
int idx = lcdGetPixelIndex_ArrayBuffer(gfx,x,y,pixelCount);
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, buf, idx>>3 );
if (gfx->data.bpp < 8) {
idx = idx & 7;
int mask = (1<<gfx->data.bpp)-1;
int existing = jsvArrayBufferIteratorGetIntegerValue(&it);
jsvArrayBufferIteratorSetIntegerValue(&it, (existing&~(mask<<idx)) | ((col&mask)<<idx));
} else {
int i;
for (i=0;i<gfx->data.bpp;i+=8) {
jsvArrayBufferIteratorSetIntegerValue(&it, col >> i);
jsvArrayBufferIteratorNext(&it);
short p;
for (p=0;p<pixelCount;p++) { // writing individual bits
if (gfx->data.bpp < 8) {
idx = idx & 7;
unsigned int mask = (unsigned int)(1<<gfx->data.bpp)-1;
unsigned int existing = (unsigned int)jsvArrayBufferIteratorGetIntegerValue(&it);
jsvArrayBufferIteratorSetIntegerValue(&it, (existing&~(mask<<idx)) | ((col&mask)<<idx));
if (gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE) {
jsvArrayBufferIteratorNext(&it);
} else {
idx += gfx->data.bpp;
if (idx>=8) jsvArrayBufferIteratorNext(&it);
}
} else { // we're writing whole bytes
int i;
for (i=0;i<gfx->data.bpp;i+=8) {
jsvArrayBufferIteratorSetIntegerValue(&it, col >> i);
jsvArrayBufferIteratorNext(&it);
}
}
}
jsvArrayBufferIteratorFree(&it);
@ -73,6 +83,33 @@ void lcdSetPixel_ArrayBuffer(JsGraphics *gfx, short x, short y, unsigned int col
}
}
void lcdSetPixel_ArrayBuffer(JsGraphics *gfx, short x, short y, unsigned int col) {
if (x>=0 && y>=0 && x<gfx->data.width && y<gfx->data.height)
lcdSetPixels_ArrayBuffer(gfx,x,y,1,col);
}
void lcdFillRect_ArrayBuffer(struct JsGraphics *gfx, short x1, short y1, short x2, short y2) {
if (x1>x2) {
short t = x1;
x1 = x2;
x2 = t;
}
if (y1>y2) {
short t = y1;
y1 = y2;
y2 = t;
}
if (x1<0) x1=0;
if (y1<0) y1=0;
if (x2>=gfx->data.width) x2 = (short)(gfx->data.width - 1);
if (y2>=gfx->data.height) y2 = (short)(gfx->data.height - 1);
if (x2<x1 || y2<y1) return; // nope
short y;
for (y=y1;y<=y2;y++)
lcdSetPixels_ArrayBuffer(gfx, x1, y, (short)(1+x2-x1), gfx->data.fgColor);
}
void lcdInit_ArrayBuffer(JsGraphics *gfx) {
// create buffer
JsVar *buf = jswrap_arraybuffer_constructor(gfx->data.width * gfx->data.height * gfx->data.bpp / 8);
@ -83,5 +120,5 @@ void lcdInit_ArrayBuffer(JsGraphics *gfx) {
void lcdSetCallbacks_ArrayBuffer(JsGraphics *gfx) {
gfx->setPixel = lcdSetPixel_ArrayBuffer;
gfx->getPixel = lcdGetPixel_ArrayBuffer;
// TODO: Optimised fill?
gfx->fillRect = lcdFillRect_ArrayBuffer;
}

View File

@ -0,0 +1,9 @@
// ArrayBuffer rect test
var LCD = Graphics.createArrayBuffer(8,8,8);
LCD.fillRect(2,2,5,5);
//console.log(LCD.buffer);
for (i=0;i<8;i++)
print(new Uint8Array(LCD.buffer,i*8,8));
result = LCD.buffer == "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0";