diff --git a/sdl/sdl-display.cpp b/sdl/sdl-display.cpp index 58c341f..9fc2793 100644 --- a/sdl/sdl-display.cpp +++ b/sdl/sdl-display.cpp @@ -9,8 +9,8 @@ #include "apple/appleui.h" -#define SCREENINSET_X (18*2) -#define SCREENINSET_Y (13*2) +#define SCREENINSET_X (18*SDLDISPLAY_SCALE) +#define SCREENINSET_Y (13*SDLDISPLAY_SCALE) // RGB map of each of the lowres colors const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black @@ -85,8 +85,8 @@ void SDLDisplay::drawImageOfSizeAt(const uint8_t *img, for (uint16_t x=0; x>1)*SDLDISPLAY_SCALE]; + + uint8_t newColor = (uint16_t) (origColor + color) / 2; + + if (x==1 && y==0) { + printf("origcolor: %d color: %d newcolor: %d\n", origColor, color, newColor); + } + cacheDoubleWidePixel(x>>1,y,newColor); + // Else if it's black, we leave whatever was in the other pixel. + } else { + // The even pixels always draw. + cacheDoubleWidePixel(x>>1,y,color); + } + + } else { + // we have enough resolution to show all the pixels, so just do it + x = (x * SDLDISPLAY_SCALE)/2; + for (int yoff=0; yoff> 3)) +#define _565toR(c) ( ((c) & 0xF800) >> 8 ) +#define _565toG(c) ( ((c) & 0x07E0) >> 5 ) +#define _565toB(c) ( ((c) & 0x001F) ) ILI9341_t3 tft = ILI9341_t3(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO); @@ -302,26 +305,79 @@ void TeensyDisplay::cache2DoubleWidePixels(uint16_t x, uint16_t y, dmaBuffer[y+VOFFSET][x+1+HOFFSET] = loresPixelColors[colorA&0xF]; } +inline double logfn(double x) +{ + // At a value of x=255, log(base 1.022)(x) is 254.636. + return log(x)/log(1.022); +} + + +inline uint16_t blendColors(uint16_t a, uint16_t b) +{ + // Straight linear average doesn't work well for inverted text, because the + // whites overwhelm the blacks. + //return ((uint32_t)a + (uint32_t)b)/2; + +#if 0 + // Testing a logarithmic color scale. My theory was that, since our + // colors here are mostly black or white, it would be reasonable to + // use a log scale of the average to bump up the brightness a + // little. In practice, it's not really legible. + return RGBto565( (uint8_t)(logfn((_565toR(a) + _565toR(b))/2)), + (uint8_t)(logfn((_565toG(a) + _565toG(b))/2)), + (uint8_t)(logfn((_565toB(a) + _565toB(b))/2)) ); +#endif + + // Doing an R/G/B average works okay for legibility. It's not great for + // inverted text. + return RGBto565( (_565toR(a) + _565toR(b))/2, + (_565toG(a) + _565toG(b))/2, + (_565toB(a) + _565toB(b))/2 ); + +} + // This is the full 560-pixel-wide version -- and we only have 280 // pixels in our buffer b/c the display is only 320 pixels wide // itself. So we'll divide x by 2. On odd-numbered X pixels, we also -// alpha-blend -- "black" means "clear" +// blend the colors of the two virtual pixels that share an onscreen +// pixel void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color) { - if (/*x&*/1) { - // divide x by 2, then this is mostly cacheDoubleWidePixel. Except - // we also have to do the alpha blend so we can see both pixels. - - uint16_t *p = &dmaBuffer[y+VOFFSET][(x>>1)+HOFFSET]; - uint16_t destColor = loresPixelColors[color]; - - // if (color == 0) - // destColor = *p; // retain the even-numbered pixel's contents ("alpha blend") - // Otherwise the odd-numbered pixel's contents "win" as "last drawn" - // FIXME: do better blending of these two pixels. - - dmaBuffer[y+VOFFSET][(x>>1)+HOFFSET] = destColor; +#if 0 + static uint8_t previousColor = 0; +#endif + if (x&1) { + // Blend the two pixels. This takes advantage of the fact that we + // always call this linearly for 80-column text drawing -- we never + // do partial screen blits, but always draw at least a whole character. + // So we can look at the pixel in the "shared" cell of RAM, and come up + // with a color between the two. + +#if 1 + // This is straight blending, R/G/B average + uint16_t origColor = dmaBuffer[y+VOFFSET][(x>>1)+HOFFSET]; + uint16_t newColor = loresPixelColors[color]; + cacheDoubleWidePixel(x>>1, y, blendColors(origColor, newColor)); +#endif + +#if 0 + // The model we use for the SDL display works better, strangely - it keeps + // the lores pixel index color (black, magenda, dark blue, purple, dark + // green, etc.) until render time; so when it does the blend here, it's + // actually blending in a very nonlinear way - e.g. "black + white / 2" + // is actually "black(0) + white(15) / 2 = 15/2 = 7 (light blue)". Weird, + // but definitely legible in a mini laptop SDL window with the same scale. + // Unfortunately, it doesn't translate well to a ILI9341 panel; the pixels + // are kind of muddy and indistinct, so the blue spills over and makes it + // very difficult to read. + uint8_t origColor = previousColor; + uint8_t newColor = (uint16_t)(origColor + color) / 2; + cacheDoubleWidePixel(x>>1, y, (uint16_t)color + (uint16_t)previousColor/2); +#endif } else { - cacheDoubleWidePixel(x, y, color); +#if 0 + previousColor = color; // used for blending +#endif + cacheDoubleWidePixel(x>>1, y, color); } }