/*
 * gfx_scroll_v — ВЕРТИКАЛЬНЫЙ скролл региона (mode-agnostic обёртка).
 *
 * Симметрична gfx_scroll_h, но сдвиг по Y.  Берёт чистый фон из НЕактивной
 * (теневой) страницы и копирует его со сдвигом dy по Y в активную (draw)
 * страницу.  Банк 0x50: копия = скролл + heal целевой страницы (старые
 * спрайты затираются сдвинутым фоном; см. gfx_scroll_h / guide §2).
 *
 * dy > 0 — сдвиг в сторону УВЕЛИЧЕНИЯ Y (изображение едет вниз,
 * открывается полоса сверху); dy < 0 — вверх (открывается снизу);
 * dy == 0 — чистая копия (полный heal).  Открывшуюся |dy|-полосу НЕ
 * заполняем — возвращаем в *dirty.
 *
 * РЕАЛИЗАЦИЯ — колонками, через _bgi_scroll_cols_raw (вертикальный режим
 * accel): колонку читаем с Port_Y=ys, пишем с Port_Y=yd (= ys+dy) — сдвиг
 * по Y без буфера-посредника (STOP между read и write делает промежуточный
 * OUT Port_Y безопасным; см. шапку leaf'а).  Один проход, вдвое быстрее
 * прежнего grab→blit-через-буфер.  Ширину >255 режем на банды колонок
 * (leaf сам делит их на DI-скобки по 16).  Высота колонки h = area->h−|dy|
 * (≤256, 0=256 у accel).  Перекрытия src/dst нет: стороны в разных страницах.
 */

#include "../include/sprite.h"
#include "../_bgi.h"

void gfx_scroll_v(const gfx_rect_t *area, int16_t dy, gfx_rect_t *dirty) {

    uint8_t  saved = gfx_get_bank();
    uint16_t ady   = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
    /* Строку чтения (ys) сдвигаем вниз на |dy| при сдвиге вверх, строку
     * записи (yd) — вниз на dy при сдвиге вниз; края в пределах area. */
    uint8_t  ys = (uint8_t)(area->y + ((dy < 0) ? ady : 0));
    uint8_t  yd = (uint8_t)(area->y + ((dy > 0) ? ady : 0));
    uint16_t hb = area->h - ady;                 /* строк к переносу (≤256) */

    if (hb) {                                    /* 0 = переносить нечего */
        uint8_t  hblk = (uint8_t)hb;             /* размер accel-блока: 256 => 0 */
        uint16_t w    = area->w;
        uint16_t src  = _gfx_addr_shadow_base + area->x;
        uint16_t dst  = _gfx_addr_base + area->x;

        gfx_set_bank(GFX_BANK_NORMAL);
        _bgi_begin();

        /* >255 колонок — банды (leaf 8-битный по числу колонок; 0=выход,
         * поэтому ≤255, а не 256).  Высота колонки одна на весь проход. */
        while (w) {
            uint8_t cw = (w > 255) ? 255 : (uint8_t)w;
            _bgi_scroll_cols_raw(src, dst, cw, hblk, ys, yd);
            src += cw; dst += cw; w -= cw;
        }

        _bgi_end();
        gfx_set_bank(saved);
    }

    if (dirty) {
        dirty->x = area->x;
        dirty->y = (dy >= 0) ? area->y : (int16_t)(area->y + area->h - ady);
        dirty->w = area->w;
        dirty->h = ady;
    }
}
