ThingPulse / esp8266-oled-ssd1306

Driver for the SSD1306 and SH1106 based 128x64, 128x32, 64x48 pixel OLED display running on ESP8266/ESP32
https://thingpulse.com
Other
1.99k stars 637 forks source link

someone able to help me integrate cropping of characters? #269

Closed ben-mkiv closed 4 years ago

ben-mkiv commented 4 years ago

Hi, i want to add the ability to crop characters to be able to render smooth vertical scrolling text on the display

i'm struggling to figure out how to mask the bits of the font (which works in some cases but sometimes things get weird... (see the picture)

cropBytes[] holds a bitmask of "pixels" which shouldn't be rendered and gets merged with currentByte before writing it to the display buffer currentByte &= ~(cropBytes[i % rasterHeight]);

I've tried to play around with initYOffset, but that didn't help much, or i did it wrong, so any help/hints are appreciated

void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height,
                                      const uint8_t *data, uint16_t offset, uint16_t bytesInData,
                                      uint16_t xMin, uint16_t yMin, uint16_t xMax, uint16_t yMax) {

    uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
    int8_t yOffset = yMove & 7;

    bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData;

    int16_t initYMove = yMove;
    int8_t initYOffset = yOffset;

    uint8_t cropBytes[rasterHeight];

    for(int i=0; i < rasterHeight; i++){
        cropBytes[i] = 0;
    }

    for(int p = 0; p < yMin && p/8 < rasterHeight; p++){
        cropBytes[p/8] |= 1 << p;
    }

    for(int p = rasterHeight*8; p > yMax; --p){
        cropBytes[p/8] |= 1 << p;
    }

    for (uint16_t i = 0; i < bytesInData; i++) {
        uint16_t charX = i / rasterHeight;

        // Reset if next horizontal drawing phase is started.
        if (i % rasterHeight == 0) {
            yMove = initYMove;
            yOffset = initYOffset;
        }

        uint8_t currentByte = pgm_read_byte(data + offset + i);

        int16_t xPos = xMove + charX;
        int16_t yPos = ((yMove >> 3) + i % rasterHeight) * this->width();

        int16_t dataPos = xPos + yPos;

        currentByte &= ~(cropBytes[i % rasterHeight]);

        switch (this->color) {
            case WHITE:   buffer[dataPos] |= currentByte << yOffset; break;
            case BLACK:   buffer[dataPos] &= ~(currentByte << yOffset); break;
            case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
        }

        if(yOffset < 0){
            // Prepare for next iteration
            yMove -= 8;   // move one block up
            yOffset += 8; // and set new yOffset
        }
        else if (dataPos + this->width() < displayBufferSize) {
            switch (this->color) {
                case WHITE:   buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break;
                case BLACK:   buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break;
                case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break;
            }
        }
    }
}

(edit: removed early breaks from the method, as they are irrelevant for the problem)

ben-mkiv commented 4 years ago

nvm, im stupid... had to shift by p%8 :>