codewitch-honey-crisis / gfx

GFX is a device independent graphics library primarily intended for IoT MCUs but not limited to that.
https://honeythecodewitch.com/gfx
MIT License
110 stars 10 forks source link

Black Pixel next to left side of first drawn sprite pixel per row #17

Closed fschuetz closed 1 year ago

fschuetz commented 1 year ago

Using esp-idf. When drawing a sprite, there is one black pixel drawn to the left of each first pixel that is masked (see attached image).

To reproduce:

  1. Fill lcd with a color (eg. drawing a rectangle in red)
  2. Draw sprite on screen.

Foto of sprite displayed on st7735 lcd screen.

My code to make this effect happen:

Destination *lcd = (Destination *)param; // As I hand the lcd as a pointer. Nothing fancy here.

        // Create Snakehead sprite
        // declare a monochrome bitmap.
        using mask_type = bitmap<gsc_pixel<1>>;
        constexpr static const size16 snakehead_size(32, 32); 

        // instantiate the bitmaps and 
        // draw the mask to the mask bitmap,
        mask_type *snakehead_mask = NULL;  
        snakehead_mask = (mask_type *)malloc(sizeof(mask_type));
        if(snakehead_mask != NULL) {
            snakehead_mask = new (snakehead_mask) mask_type(snakehead_size, (uint8_t *)snake_head_32x32_mask);//snakehead_mask_buf); 
        } else {
            ESP_LOGE(TAG_MOD_SNAKE, "Not enough free memory.");
            return -1;
        }

        // and the sprite to the bmp bitmap
        bmp_type *snakehead_bmp = NULL;
        snakehead_bmp = (bmp_type *)malloc(sizeof(bmp_type));
        if(snakehead_bmp != NULL) {
            snakehead_bmp = new (snakehead_bmp) bmp_type(snakehead_size, (uint8_t *)snake_head_bw_32x32_data);//snakehead_bmb_buf);
        } else {
            ESP_LOGE(TAG_MOD_SNAKE, "Not enough free memory.");
            return -1;
        }

        // declare the sprite:
        using sprite_type = sprite<rgb_pixel<16>>;
        sprite_type sprite(snakehead_size,snakehead_bmp->begin(),snakehead_mask->begin());

        // show sprite static on red background
        draw::filled_rectangle(*lcd, lcd->bounds(), color<rgb_pixel<16>>::red);
        draw::sprite(*lcd, spoint16(10,50), sprite);
        vTaskDelay(pdMS_TO_TICKS(10000));

My mask data is:

const uint8_t snake_head_32x32_mask[] = {
    0x00, 0x0F, 0xF0, 0x00, 
    0x00, 0x0F, 0xF0, 0x00,
    0x00, 0x0F, 0xF0, 0x00,
    0x00, 0x0F, 0xF0, 0x00,

    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,

    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,

    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,

    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,
    0x0F, 0xFF, 0xFF, 0xF0,

    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0x00,

    0x00, 0x0F, 0xF0, 0x00, 
    0x00, 0x0F, 0xF0, 0x00,
    0x00, 0x0F, 0xF0, 0x00,
    0x00, 0x0F, 0xF0, 0x00
};

My sprite data is:

const uint8_t snake_head_bw_32x32_data[] {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0010 (16) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0020 (32) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0030 (48) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0040 (64) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0050 (80) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0060 (96) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0070 (112) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0080 (128) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x0090 (144) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x00A0 (160) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x00B0 (176) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x00C0 (192) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x00D0 (208) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x00E0 (224) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x00F0 (240) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0100 (256) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x0110 (272) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0120 (288) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x0130 (304) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0140 (320) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x0150 (336) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0160 (352) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x0170 (368) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0180 (384) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x0190 (400) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x01A0 (416) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x01B0 (432) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x01C0 (448) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x01D0 (464) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x01E0 (480) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x01F0 (496) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0200 (512) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x0210 (528) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0220 (544) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x0230 (560) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0240 (576) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x0250 (592) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0260 (608) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A,   // 0x0270 (624) pixels
    0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x9F, 0x2A, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0280 (640) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x0290 (656) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x02A0 (672) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x02B0 (688) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x02C0 (704) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x02D0 (720) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x02E0 (736) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6,   // 0x02F0 (752) pixels
    0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x6D, 0xE6, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0300 (768) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x0310 (784) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0320 (800) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x0330 (816) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0340 (832) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x0350 (848) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0360 (864) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD,   // 0x0370 (880) pixels
    0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0x3C, 0xAD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0380 (896) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0390 (912) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03A0 (928) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03B0 (944) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03C0 (960) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03D0 (976) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03E0 (992) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x03F0 (1008) pixels
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   // 0x0400 (1024) pixels
};
codewitch-honey-crisis commented 1 year ago

thanks. I'll see if I can reproduce this. I don't have an ST7735 anymore but I'll try it on another display.

If I can't reproduce it either way, I'll let you know. It's possibly a driver issue, and I haven't been maintaining the ESP-IDF drivers as ESP-IDF has a number of limitations. Instead these days, I'm using https://github.com/codewitch-honey-crisis/uix on top of GFX and then using Espressif's ESP Panel API to draw to the display, similar to how you'd do with LVGL. Since you're obviously using GFX pretty routinely, if you want I can show you how to use UIX on top of it. It gives you widgets, but more importantly, it can draw on demand, meaning it never needs to read back from the display, and also isn't hamstrung by some of the other limitations of the IDF when it comes to driving displays. Either way, I'll investigate this issue, and thank you.

fschuetz commented 1 year ago

Thanks for looking into it. I started to look into the code as well. I could not yet wrap my head around it, but one thing that seems at least odd to me is that in the function

        template<typename Destination,typename Sprite>
        static gfx_result sprite_impl(Destination& destination, const spoint16& location, const Sprite& source,srect16* clip = nullptr,bool async=false) {

of gfx_drawing.hpp:1990ff

When starting to loop through the x values, opx and px are defined on line 1999. When the first set pixel in the mask is hit, then line 2004 evaluates to true and so does 2005:

2004     if (source.hit_test(pt)) {
2005              if (-1 == run_start) {
2006                        run_start = x;
2007                        opx = px;
2008.              }

On line 2007, opx is set to the uninitialised px.

2009           source.point(pt, &px);
2010            if (opx != px) {
2011                         if (run_start != -1) {
2012                            line_impl(destination, {int16_t(run_start + location.x), pt2.y, int16_t(x + location.x - 1), pt2.y}, opx, clip, async);
2013                        }
2014                        opx = px;
2015                        run_start = x;
2016                    }
                    destination.point((point16)pt2, px);

The if on 2010 therefore could be true or false indeterministic. If it evaluates to false, as this is likely, it would then lead a line of length one pixel being drawn with the (random) color of opx.

However, I think my analysis has a flaw, as the pixels of the mask are perfectly drawn and the black pixel is one before the mask starts.

EDIT: Though, I draw to location (10,50) and the first black pixel in the first row is (22,50). This pixel should be white (white looks blue on the photo). The first white pixel is (23,50) and the last pixel drawn is (30,50) - one "too late".

EDIT2: Looking at the code some more it becomes less and less clear to me what the check at 2010 is supposed to achieve. The line is drawn from (22,50) to (21,50). However, the color is black, as opx=px from line 2017 is not initialised and in my compilation happens to be 0. However, on line 2017 we set the pixel pt2 which is (22,50) to white. This leaves pixel 21 that was drawn black by the line. This happens on every new line.

Also I added printfs to the function above, and the first draw operation is line 2012 drawing a line from (22,50) to (21,50), which is off by one.

Wanted to let you know anyways. Will continue looking.

I use your gfx as it is the one that perfectly fits my needs. I built some easy to generate menu/submenu modules etc... on it. So currently I am not keen on switching, especially as I am finishing up a project based on it. However, happy to learn more about UIX in due course.

codewitch-honey-crisis commented 1 year ago

Your code to create the bitmaps is curious, and forgive me, it seems like maybe you don't quite understand how to use them. You would not use "new" or malloc" on these objects typically. Rather, you pass in a buffer to them. the bitmap class itself is light weight, no matter the size the bitmap, and can be safely kept on the stack. The buffer you pass in to the constructor is the bitmap's main memory. You should be using const_bitmaps to wrap those const arrays.

However, there was a bug in GFX where I did not let you initialize a sprite with consts. I've just fixed that in 1.6 (being tested and published as I write this)

I could not reproduce your problem when I did it this way - at least under arduino. I haven't tried it under the IDF yet - since you have a different screen than me can you try running this code against the latest GFX? (adapt for the IDF as necessary)

// Create Snakehead sprite
// declare a monochrome bitmap.
using mask_type = const_bitmap<gsc_pixel<1>>;
using bmp_type = const_bitmap<rgb_pixel<16>>;
constexpr static const size16 snakehead_size(32, 32); 

// instantiate the bitmaps and 
// draw the mask to the mask bitmap,
mask_type snakehead_mask(snakehead_size,snake_head_32x32_mask);

// and the sprite to the bmp bitmap
bmp_type snakehead_bmp(snakehead_size,snake_head_bw_32x32_data);

// declare the sprite:
using sprite_type = sprite<rgb_pixel<16>>;
sprite_type sprite(snakehead_size,snakehead_bmp.begin(),snakehead_mask.begin());

// show sprite static on red background
draw::filled_rectangle(lcd, lcd.bounds(), color<rgb_pixel<16>>::red);
draw::sprite(lcd, spoint16(10,50), sprite);
//vTaskDelay(pdMS_TO_TICKS(10000));

Or an even shorter version

constexpr static const size16 snakehead_size(32, 32); 

// declare the sprite:
using sprite_type = sprite<rgb_pixel<16>>;
sprite_type sprite(snakehead_size,snake_head_bw_32x32_data,snake_head_32x32_mask);

// show sprite static on red background
draw::filled_rectangle(lcd, lcd.bounds(), color<rgb_pixel<16>>::red);
draw::sprite(lcd, spoint16(10,50), sprite);
//vTaskDelay(pdMS_TO_TICKS(10000));
fschuetz commented 1 year ago

I will try this tomorrow. Maybe you want to check my edit EDIT2 above, which I submitted just as you did.

fschuetz commented 1 year ago

Commenting out line 2012 fixes the drawing...

fschuetz commented 1 year ago

The problem occurs if I use your code. My allocation is ok. I could allocate on the stack, but I decided to allocate on the heap as I want to preserve stack memory as I have a pretty deep call stack. Also, I use placement new as I do not have exceptions in c++ switched on to preserve code size. Then the safest is to preallocate the memory for an object and use placement new if the allocation succeeds. If using new(), then the code crashes is the allocation fails. But as I said, even if I use your on stack allocation with the newest codebase, the problem remains. I think I found the issue, though.

To the problem:

I am very sure I found the source of the problem. Its in the sprite_impl() function at line 1990ff as mentioned above. It is a combination of the missing initialisation of px and opx and the offset calculation for the line_impl() call. I think the reason why you cannot reproduce the error is due to the differences in the compiler / platform we use. My assumption would be your compiler does not initialise memory to zero and px and opx have some values that are different (could you verify by adding a printf("\nopx: %d, px: %d\n", opx.value(), px.value()). In my case, both variables are unitialised but contain the value 0. For every line, when source.hit_test(pt) evaluates to true, run_start must be -1 and thus the if(-1 == run_start) on line 2005 evaluates to true. This then sets run_start to the x value of the current pixel in the sprite opx to the same value as px (which in my case is 0 = black for the uninitialised px). Next, the pixel value from the sprite is fetched into px (line 2009, source.point(pt, %px)). Now if(opx != px) will evaluate. In my case, opx has a value of 0, pt will have a value of 0xFFFF due to the 16 bit value of the pixel in the sprite. run_start is not -1 as we just set it to x. So we end up calling line_impl(). At this point I see three problems. First, we should not yet call line_impl(): I assume drawing a horizontal line of the same pixel values is more efficient than drawing individual pixels. So we should only end up here, after the (in case of the first line of my sprite) 8 pixels that should be drawn. The check is wrong. The second problem is, that we draw the line as follows: {int16_t(run_start + location.x), pt2.y, int16_t(x + location.x - 1), pt2.y}. This means, that we draw the line from the location of the pixel (run_start denotes the number of the pixel (x in this case (which is 12) + location.x which is the offset of the draw location (10) which evaluates to 22. Then the second x value is calculated (x + location.x -1), which ist the same as the previous expression (as run_start = x) minus 1. So the line is drawn from (x,y) to (x-1, y). And it is drawn with the value of opx, which is not initialised (as it was set to x which was not initialised) which was 0 = black in the case of my compiler. Why you cannot reproduce it, I have two theories: Your px value could be non-zero or even a color close to white and thus you don't see the additional pixel, or due to some accident, px was indeed initialised to 0xFFFF by your compiler and thus the if does not trigger and line_impl() is not called. Maybe if you could add some printfs to show the values that would be great to reproduce. We then continue, and this is where i see another issue that maybe is not as intended. We just drew a two pixel black line. On line 2017, destionation.point((point16)pt2, px) is called. Unconditionally, so even after drawing the line. I assume this is not as intended. However, this will draw the correct first pixel at the correct location (and also do that in each subsequent call). This is why I only see one black pixel left to the actual sprite position of the first to be drawn pixel of each line, the other black pixel is overwritten at the correct position with the correct pixel. This is also the reason, why an easy fix is just commenting out the drawing of the line, as effectively this optimisation is ignored and a pixel by pixel draw happens anyways. I think instead of "looking back" on the pixels a "look ahead" approach would be easier. Can you confirm, that drawing the line is intended as an optimisation? I would then tomorrow propose an implementation that fixes the issue.

Also, another way to see the effect in case of absence of magnification to count pixels is to fill the screen and draw the sprite as done above. Then draw a rectangle exactly (!) the size of the sprite over the sprite (Could be red, but any color really to see what happens). Then move the sprite one pixel to the right. Draw exactly over the sprite and so on. This will drag a black line behind the sprite in the "center (lines 13-20)" where the first drawable pixel is the first on the line, as the line with black pixels will draw to -1 offset which will not be cleared with the drawn over rectangle. (This is how I discovered the effect, as I initially drew to a bmp where I wanted to restore the background and then move the sprite one pixel:

rect16 snake_head_bounds = sprite.bounds();
rect16 snake_location = rect16(10,50,snake_head_bounds.x2+10, snake_head_bounds.y2+50);
for(int i = 10; i < 100; i++) {
            draw::sprite(*lcd, snake_location.location(), sprite);
            vTaskDelay(pdMS_TO_TICKS(1000));
            draw::filled_rectangle(*lcd, snake_location, color<typename Destination::pixel_type>::blue);
            ++snake_location.x1;
            ++snake_location.x2;
            vTaskDelay(pdMS_TO_TICKS(100));
}
codewitch-honey-crisis commented 1 year ago

Thanks so much. I'll take a look at this just as soon as I'm able to today.

codewitch-honey-crisis commented 1 year ago

I've had some work come up and pushed this back for me some. If I were you I'd implement your temporary fix and after I investigate the next thing I'll do is roll out a fix so you'll get it with the next version. Out of curiosity, are you using this with platformIO?

fschuetz commented 1 year ago

I've had some work come up and pushed this back for me some. If I were you I'd implement your temporary fix and after I investigate the next thing I'll do is roll out a fix so you'll get it with the next version. Out of curiosity, are you using this with platformIO?

Don't worry. I was distracted as well. I will provide the fix once done. I was also thinking, that maybe instead of only using lines for optimisation, segmenting a sprite in squares (either by divide and conquer or dynamic programming) could be even more efficient in terms of writes (depending on the implementation of filled squares - which I could not yet check), trading off some additional memory requirements. I'll do the easy fix first in my mirror and test it. Once it proves working I will let you know. Unfortunately, I think I can't send a pull request as I am using gitlab for the mirror and this does not play well with github? I will just paste the code here.

And yes, I am using plattformio, but I use a personal mirror of your git as included library in my code. I keep this one in sync with yours, but it allows me to make changes in own branches (mostly printfs and comments) if I encounter things I don't understand at first sight. Whenever encountering a potential bug, I make sure I have the last version of yours to test with - and use the fix until you deploy it - which in the past was pretty useless as you are super quick :-). Wish all maintainers of sw were that responsive.

codewitch-honey-crisis commented 1 year ago

I updated the code with 1.61. I rewrote the RLE. Rectangles would potentially be quicker but subdividing them takes more CPU so I figure it's kind of a wash. With my rewrite the snakes head looks more like a snake and less like a diamond. I think my RLE code was a mess. Can you give this a shot at your earliest convenience? The reason i'm kinda rushed is it's published now, and I'm hoping i didn't break it worse! Thanks. :)

fschuetz commented 1 year ago

I updated the code with 1.61. I rewrote the RLE. Rectangles would potentially be quicker but subdividing them takes more CPU so I figure it's kind of a wash. With my rewrite the snakes head looks more like a snake and less like a diamond. I think my RLE code was a mess. Can you give this a shot at your earliest convenience? The reason i'm kinda rushed is it's published now, and I'm hoping i didn't break it worse! Thanks. :)

This change breaks it completely for me. There are lots of white and black lines instead of the sprite.

EDIT 1: One mistake is the ++y on line 2022. There is no need to move to the next line at this stage. This is taken care of by the outer loop. This fixes part of it. The rest I am still investigating.

EDIT 2: On line 2019, line_impl() should draw opx, not px. However, there is still something off. The outline overshoots (the shape should be a diamond).

EDIT 3: The second x coordinate of the line_impl call is wrong. It is run_start+x-1+location.x and it should be x-1+location.x. So the rect should be srect16(run_start+location.x,y+location.y,run_start+x-1+location.x,y+location.y)

codewitch-honey-crisis commented 1 year ago

okay. I'll take care of it. Problem is I didn't know what your shape was supposed to look like

fschuetz commented 1 year ago

okay. I'll take care of it. Problem is I didn't know what your shape was supposed to look like

This is the fixed function:

template <typename Destination, typename Sprite>
    static gfx_result sprite_impl(Destination& destination, const spoint16& location, const Sprite& source, const srect16* clip = nullptr, bool async = false) {
        static_assert(helpers::is_same<typename Destination::pixel_type, typename Sprite::pixel_type>::value, "Sprite and Destination pixel types must be the same");
        const size16 size = source.dimensions();
        const srect16 db;
        // suspend if we can
        helpers::suspender<Destination, Destination::caps::suspend, Destination::caps::async> stok(destination, false);

        for (int y = 0; y < size.height; ++y) {
            int run_start=-1;
            typename Sprite::pixel_type px(0,true), opx(0,true);
            //for (int x = 0; x < size.width; ++x) {
            int x = 0;
            while(x<size.width) {
                run_start = -1;
                //const spoint16 pt2 = ((spoint16)pt).offset(location.x, location.y);
                //const point16 pt = point16(uint16_t(x), uint16_t(y));
                while(x<size.width) {
                    while(!source.hit_test(point16(x,y)) && x<size.width) {
                        ++x;
                    }
                    if(x<size.width) {
                        run_start = x;                        
                        source.point(point16(x,y),&px);
                        opx=px;
                        while(x<size.width && source.hit_test(point16(x,y)) && opx==px) {
                            opx=px;
                            ++x;
                            source.point(point16(x,y),&px);
                        }
                        line_impl(destination,srect16(run_start+location.x,y+location.y,x-1+location.x,y+location.y),opx,clip,async);
                    }
                }
                //++y;
            }
        }

        return gfx_result::success;
    }
codewitch-honey-crisis commented 1 year ago

Tried it, it works, so I pushed it. Thanks for your help. =)

fschuetz commented 1 year ago

Tried it, it works, so I pushed it. Thanks for your help. =)

No problem. Quick question: If I understand correctly, sprite rotation is not supported?

codewitch-honey-crisis commented 1 year ago

No it's not. Viewports were supposed to handle that, but in practice they don't work right due to rounding errors. :(