e2730f78e0
Вертикальный скролл перестал ходить через строку-буфер на стеке: колонку читаем с Port_Y=ys, пишем с Port_Y=yd, а STOP между read- и write-триггером делает промежуточный OUT Port_Y безопасным. Один проход вместо grab→blit-через-буфер. Справочник libc приведён в соответствие (там же строка про новую точку входа cbl_open_silence). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
121 lines
5.0 KiB
C
121 lines
5.0 KiB
C
/*
|
||
* 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) {
|
||
#ifdef GFX_NOCHECK
|
||
uint8_t saved = gfx_get_bank();
|
||
uint16_t ady = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
|
||
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;
|
||
|
||
if (hb) {
|
||
uint8_t hblk = (uint8_t)hb;
|
||
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();
|
||
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;
|
||
}
|
||
#else
|
||
int16_t x, y;
|
||
uint16_t aw, ah, cut, ady, hb;
|
||
uint8_t saved, ys, yd;
|
||
|
||
if (!area) return;
|
||
x = area->x; y = area->y; aw = area->w; ah = area->h;
|
||
if (!aw || !ah) goto empty;
|
||
if (x < 0) {
|
||
cut = (uint16_t)(-x);
|
||
if (cut >= aw) goto empty;
|
||
aw -= cut; x = 0;
|
||
}
|
||
if (y < 0) {
|
||
cut = (uint16_t)(-y);
|
||
if (cut >= ah) goto empty;
|
||
ah -= cut; y = 0;
|
||
}
|
||
if (x >= GFX_WIDTH || y >= GFX_HEIGHT) goto empty;
|
||
if (aw > (uint16_t)(GFX_WIDTH - x)) aw = (uint16_t)(GFX_WIDTH - x);
|
||
if (ah > (uint16_t)(GFX_HEIGHT - y)) ah = (uint16_t)(GFX_HEIGHT - y);
|
||
if (dy >= (int16_t)ah || dy <= -(int16_t)ah) {
|
||
if (dirty) { dirty->x=x; dirty->y=y; dirty->w=aw; dirty->h=ah; }
|
||
return;
|
||
}
|
||
|
||
ady = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
|
||
saved = gfx_get_bank();
|
||
/* Строку чтения (ys) сдвигаем вниз на |dy| при сдвиге вверх, строку
|
||
* записи (yd) — вниз на dy при сдвиге вниз; края в пределах area. */
|
||
ys = (uint8_t)(y + ((dy < 0) ? ady : 0));
|
||
yd = (uint8_t)(y + ((dy > 0) ? ady : 0));
|
||
hb = ah - ady;
|
||
|
||
if (hb) { /* 0 = переносить нечего */
|
||
uint8_t hblk = (uint8_t)hb; /* размер accel-блока: 256 => 0 */
|
||
uint16_t w = aw;
|
||
uint16_t src = _gfx_addr_shadow_base + (uint16_t)x;
|
||
uint16_t dst = _gfx_addr_base + (uint16_t)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 = x;
|
||
dirty->y = (dy >= 0) ? y : (int16_t)(y + ah - ady);
|
||
dirty->w = aw;
|
||
dirty->h = ady;
|
||
}
|
||
return;
|
||
|
||
empty:
|
||
if (dirty) { dirty->x=0; dirty->y=0; dirty->w=0; dirty->h=0; }
|
||
#endif
|
||
}
|