RLE for greyscale lcd (gives more firmware space!) (#1142)
* use RLE encodes bitmaps on 212x64 pixel radios * fix model image display fix icon display * implement RLE bitmaps in companion for splash image on 212x64 radios reserve 3kB for RLE bitmaps in firmware * fix size check * use defines instead of magic numbers * fix display of splash screens on 212x64 radios * add warning message if compressed image is larger than the reserved space
This commit is contained in:
@@ -204,6 +204,10 @@ bool loadModelBitmap(char * name, uint8_t * bitmap)
|
||||
}
|
||||
|
||||
// In all error cases, we set the default logo
|
||||
memcpy(bitmap, logo_taranis, MODEL_BITMAP_SIZE);
|
||||
RleBitmap pic(logo_taranis, 0);
|
||||
*bitmap++ = pic.getWidth();
|
||||
*bitmap++ = pic.getRawRows();
|
||||
for(int i=0; i < MODEL_BITMAP_SIZE-2; i++)
|
||||
*bitmap++ = pic.getNext();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -976,4 +976,39 @@ void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset, co
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lcdDrawRleBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset, coord_t width)
|
||||
{
|
||||
RleBitmap pic(img, offset);
|
||||
|
||||
uint8_t w = pic.getWidth();
|
||||
if (!width || width > w) {
|
||||
width = w;
|
||||
}
|
||||
if (x+width > LCD_W) {
|
||||
if (x >= LCD_W ) return;
|
||||
width = LCD_W-x;
|
||||
}
|
||||
uint8_t rows = pic.getRows();
|
||||
|
||||
for (uint8_t row=0; row<rows; row++) {
|
||||
uint8_t *p = &displayBuf[(row + (y/2)) * LCD_W + x];
|
||||
for (coord_t i=0; i<width; i++) {
|
||||
if (p >= DISPLAY_END) return;
|
||||
uint8_t b = pic.getNext();
|
||||
if (y & 1) {
|
||||
*p = (*p & 0x0f) + ((b & 0x0f) << 4);
|
||||
if ((p+LCD_W) < DISPLAY_END) {
|
||||
*(p+LCD_W) = (*(p+LCD_W) & 0xf0) + ((b & 0xf0) >> 4);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*p = b;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
pic.goToNextRow();
|
||||
pic.skip(offset);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,9 @@ void drawTelemetryTopBar();
|
||||
void lcdDraw1bitBitmap(coord_t x, coord_t y, const unsigned char * img, uint8_t idx, LcdFlags att=0);
|
||||
|
||||
void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t width=0);
|
||||
#define LCD_ICON(x, y, icon) lcdDrawBitmap(x, y, icons, icon)
|
||||
void lcdDrawRleBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t width=0);
|
||||
#define LCD_ICON(x, y, icon) lcdDrawRleBitmap(x, y, icons, icon)
|
||||
|
||||
|
||||
void lcdClear();
|
||||
|
||||
@@ -193,4 +195,75 @@ inline pixel_t getPixel(unsigned int x, unsigned int y)
|
||||
|
||||
uint8_t getTextWidth(const char * s, uint8_t len=0, LcdFlags flags=0);
|
||||
|
||||
class RleBitmap
|
||||
{
|
||||
public:
|
||||
RleBitmap(const uint8_t *src, coord_t offset) :
|
||||
state(RLE_FIRST_BYTE), src(src), curPtr(src), byte(0), curCount(0), pos(0)
|
||||
{
|
||||
width = *curPtr++;
|
||||
rawRows = *curPtr++;
|
||||
rows = (rawRows +1)/2;
|
||||
skip(offset);
|
||||
}
|
||||
|
||||
void skip(coord_t count)
|
||||
{
|
||||
while(count)
|
||||
{
|
||||
count--;
|
||||
getNext();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getNext()
|
||||
{
|
||||
pos++;
|
||||
switch(state)
|
||||
{
|
||||
case RLE_FIRST_BYTE:
|
||||
byte = *curPtr++;
|
||||
if(byte == *curPtr)
|
||||
state = RLE_SECOND_BYTE;
|
||||
break;
|
||||
case RLE_SECOND_BYTE:
|
||||
byte = *curPtr++;
|
||||
curCount = (*curPtr++)+1;
|
||||
state = RLE_CONTINUE;
|
||||
// fall through
|
||||
case RLE_CONTINUE:
|
||||
curCount--;
|
||||
if(!curCount)
|
||||
state = RLE_FIRST_BYTE;
|
||||
break;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
uint8_t getWidth() const { return width; }
|
||||
uint8_t getRows() const { return rows; }
|
||||
uint8_t getRawRows() const { return rawRows; }
|
||||
void goToNextRow()
|
||||
{
|
||||
coord_t offset = pos%width;
|
||||
if(offset)
|
||||
skip(width - pos%width);
|
||||
}
|
||||
|
||||
private:
|
||||
enum State {RLE_FIRST_BYTE, RLE_SECOND_BYTE, RLE_CONTINUE} state;
|
||||
const uint8_t* src;
|
||||
const uint8_t* curPtr;
|
||||
|
||||
uint8_t width;
|
||||
uint8_t rows;
|
||||
uint8_t rawRows;
|
||||
|
||||
uint8_t byte;
|
||||
uint16_t curCount;
|
||||
|
||||
coord_t pos;
|
||||
};
|
||||
|
||||
|
||||
#endif // _LCD_H_
|
||||
|
||||
@@ -28,7 +28,7 @@ const unsigned char ASTERISK_BITMAP[] = {
|
||||
void drawAlertBox(const char * title, const char * text, const char * action)
|
||||
{
|
||||
lcdClear();
|
||||
lcdDrawBitmap(0, 0, ASTERISK_BITMAP);
|
||||
lcdDrawRleBitmap(0, 0, ASTERISK_BITMAP);
|
||||
|
||||
#define MESSAGE_LCD_OFFSET 60
|
||||
|
||||
|
||||
@@ -22,16 +22,21 @@
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(SPLASH)
|
||||
const unsigned char splashdata[] = {
|
||||
'S','P','S',0,
|
||||
#include "bitmaps/212x64/splash.lbm"
|
||||
'S','P','E',0 };
|
||||
const unsigned char * const splash_lbm = splashdata+4;
|
||||
#define MAXIMUM_SPLASH_IMAGE_SIZE 3072
|
||||
struct {
|
||||
const uint8_t __magic_prefix[4] = { 'S','P','S',0 };
|
||||
const uint8_t splashdata[MAXIMUM_SPLASH_IMAGE_SIZE] = {
|
||||
#include "bitmaps/212x64/splash.lbm"
|
||||
};
|
||||
const uint8_t __magic_suffix[4] = { 'S','P','E',0 };
|
||||
} splash_struct;
|
||||
static_assert(sizeof(splash_struct.splashdata) <= MAXIMUM_SPLASH_IMAGE_SIZE, "");
|
||||
const unsigned char * const splash_lbm = splash_struct.splashdata;
|
||||
|
||||
void drawSplash()
|
||||
{
|
||||
lcdClear();
|
||||
lcdDrawBitmap(0, 0, splash_lbm);
|
||||
lcdDrawRleBitmap(0, 0, splash_lbm);
|
||||
|
||||
#if MENUS_LOCK == 1
|
||||
if (readonly == false) {
|
||||
|
||||
@@ -52,9 +52,9 @@ void drawStartupAnimation(uint32_t duration, uint32_t totalDuration)
|
||||
lcdClear();
|
||||
|
||||
if (index == 0)
|
||||
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_lock, 0, ANIMATIONS_BITMAP_WIDTH);
|
||||
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_lock, 0, ANIMATIONS_BITMAP_WIDTH);
|
||||
else
|
||||
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_startup, (index - 1) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
|
||||
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_startup, (index - 1) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
|
||||
|
||||
lcdRefresh();
|
||||
}
|
||||
@@ -69,7 +69,7 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char
|
||||
lcdRefreshWait();
|
||||
lcdClear();
|
||||
|
||||
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_shutdown, (3 - index) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
|
||||
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_shutdown, (3 - index) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
|
||||
if (message) {
|
||||
lcdDrawText((LCD_W - getTextWidth(message)) / 2, LCD_H - 2*FH, message);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ void drawSleepBitmap()
|
||||
{
|
||||
lcdRefreshWait();
|
||||
lcdClear();
|
||||
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_sleep, 0);
|
||||
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_sleep, 0);
|
||||
lcdRefresh();
|
||||
lcdRefreshWait();
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ void displayTopBarGauge(coord_t x, int count, bool blinking=false)
|
||||
}
|
||||
|
||||
#define LCD_NOTIF_ICON(x, icon) \
|
||||
lcdDrawBitmap(x, BAR_Y, icons, icon); \
|
||||
lcdDrawRleBitmap(x, BAR_Y, icons, icon); \
|
||||
lcdDrawSolidHorizontalLine(x, BAR_Y+8, 11)
|
||||
|
||||
void displayTopBar()
|
||||
|
||||
Reference in New Issue
Block a user