Reduce drawCompressed progmem usage (#19)

Reduce drawCompressed() progmem usage
This commit is contained in:
Pharap 2018-01-17 18:51:34 +00:00 committed by Scott Allen
parent f8f46de06d
commit 6f6849a5bb
1 changed files with 86 additions and 87 deletions

View File

@ -845,135 +845,134 @@ void Arduboy2Base::drawSlowXYBitmap
} }
} }
typedef struct CSESSION {
int byte;
int bit;
const uint8_t *src;
int src_pos;
} CSESSION;
static CSESSION cs;
static int getval(int bits) struct BitStreamReader {
{ const uint8_t *source;
int val = 0; uint16_t sourceIndex;
int i; uint8_t bitBuffer;
for (i = 0; i < bits; i++) uint8_t byteBuffer;
BitStreamReader(const uint8_t *source)
: source(source), sourceIndex(), bitBuffer(), byteBuffer()
{ {
if (cs.bit == 0x100)
{
cs.bit = 0x1;
cs.byte = pgm_read_byte(&cs.src[cs.src_pos]);
cs.src_pos ++;
}
if (cs.byte & cs.bit)
val += (1 << i);
cs.bit <<= 1;
} }
return val;
} uint16_t readBits(uint16_t bitCount)
{
uint16_t result = 0;
for (uint16_t i = 0; i < bitCount; i++)
{
if (this->bitBuffer == 0)
{
this->bitBuffer = 0x1;
this->byteBuffer = pgm_read_byte(&this->source[this->sourceIndex]);
++this->sourceIndex;
}
if ((this->byteBuffer & this->bitBuffer) != 0)
result |= (1 << i); // result |= bitshift_left[i];
this->bitBuffer <<= 1;
}
return result;
}
};
void Arduboy2Base::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color) void Arduboy2Base::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color)
{ {
int bl, len;
int col;
int i;
int a, iCol;
int byte = 0;
int bit = 0;
int w, h;
// set up decompress state // set up decompress state
cs.src = bitmap; BitStreamReader cs = BitStreamReader(bitmap);
cs.bit = 0x100;
cs.byte = 0;
cs.src_pos = 0;
// read header // read header
w = getval(8) + 1; int width = (int)cs.readBits(8) + 1;
h = getval(8) + 1; int height = (int)cs.readBits(8) + 1;
uint8_t spanColour = (uint8_t)cs.readBits(1); // starting colour
col = getval(1); // starting colour
// no need to draw at all if we're offscreen // no need to draw at all if we're offscreen
if (sx + w < 0 || sx > WIDTH - 1 || sy + h < 0 || sy > HEIGHT - 1) if ((sx + width < 0) || (sx > WIDTH - 1) || (sy + height < 0) || (sy > HEIGHT - 1))
return; return;
// sy = sy - (frame*h); // sy = sy - (frame * height);
int yOffset = abs(sy) % 8; int yOffset = abs(sy) % 8;
int sRow = sy / 8; int startRow = sy / 8;
if (sy < 0) { if (sy < 0) {
sRow--; startRow--;
yOffset = 8 - yOffset; yOffset = 8 - yOffset;
} }
int rows = h / 8; int rows = height / 8;
if (h % 8 != 0) rows++; if ((height % 8) != 0)
++rows;
a = 0; // +(frame*rows); int rowOffset = 0; // +(frame*rows);
iCol = 0; int columnOffset = 0;
byte = 0; bit = 1; uint8_t byte = 0x00;
while (a < rows) // + (frame*rows)) uint8_t bit = 0x01;
while (rowOffset < rows) // + (frame*rows))
{ {
bl = 1; uint16_t bitLength = 1;
while (!getval(1)) while (cs.readBits(1) == 0)
bl += 2; bitLength += 2;
len = getval(bl) + 1; // span length uint16_t len = cs.readBits(bitLength) + 1; // span length
// draw the span // draw the span
for (uint16_t i = 0; i < len; ++i)
for (i = 0; i < len; i++)
{ {
if (col) if (spanColour != 0)
byte |= bit; byte |= bit;
bit <<= 1; bit <<= 1;
if (bit == 0x100) // reached end of byte if (bit == 0) // reached end of byte
{ {
// draw // draw
int bRow = startRow + rowOffset;
int bRow = sRow + a;
//if (byte) // possible optimisation //if (byte) // possible optimisation
if (bRow <= (HEIGHT / 8) - 1) if ((bRow <= (HEIGHT / 8) - 1) && (bRow > -2) && (columnOffset + sx <= (WIDTH - 1)) && (columnOffset + sx >= 0))
if (bRow > -2) {
if (iCol + sx <= (WIDTH - 1)) int16_t offset = (bRow * WIDTH) + sx + columnOffset;
if (iCol + sx >= 0) { if (bRow >= 0)
{
if (bRow >= 0) int16_t index = offset;
{ uint8_t value = byte << yOffset;
if (color)
sBuffer[(bRow * WIDTH) + sx + iCol] |= byte << yOffset; if (color != 0)
else sBuffer[index] |= value;
sBuffer[(bRow * WIDTH) + sx + iCol] &= ~(byte << yOffset); else
} sBuffer[index] &= ~value;
if (yOffset && bRow < (HEIGHT / 8) - 1 && bRow > -2) }
{ if ((yOffset != 0) && (bRow < (HEIGHT / 8) - 1))
if (color) {
sBuffer[((bRow + 1)*WIDTH) + sx + iCol] |= byte >> (8 - yOffset); int16_t index = offset + WIDTH;
else uint8_t value = byte >> (8 - yOffset);
sBuffer[((bRow + 1)*WIDTH) + sx + iCol] &= ~(byte >> (8 - yOffset));
} if (color != 0)
} sBuffer[index] |= value;
else
sBuffer[index] &= ~value;
}
}
// iterate // iterate
iCol ++; ++columnOffset;
if (iCol >= w) if (columnOffset >= width)
{ {
iCol = 0; columnOffset = 0;
a ++; ++rowOffset;
} }
// reset byte // reset byte
byte = 0; bit = 1; byte = 0x00;
bit = 0x01;
} }
} }
col = 1 - col; // toggle colour for next span spanColour ^= 0x01; // toggle colour bit (bit 0) for next span
} }
} }