/* * gfx_copy_page — копия области из НЕактивной страницы в активную: * прямая или с ПЕРЕВОРОТОМ ПО ВЕРТИКАЛИ (mode-agnostic обёртка). * * Зачем. Два сценария, оба про «взять готовую картинку целиком»: * - GFX_COPY_DIRECT — второй странице дабл-буфера отдать то, что уже * нарисовано в первой, вместо повторной отрисовки сцены (у тайловых * движков это в разы дешевле и, главное, невидимо для игрока: он * видит только готовый кадр); * - GFX_COPY_VFLIP — перевернуть уже нарисованное вверх ногами (зелье * инверсии в порте Prince of Persia). * * Направление то же, что у gfx_scroll_*: источник — НЕактивная (теневая) * страница, приёмник — активная (draw). Банк на время копии — * GFX_BANK_NORMAL (0x50): запись бьёт VRAM И ОЗУ-копию. Это не деталь, а * инвариант: accel ЧИТАЕТ ОЗУ-копию, поэтому копируется чистый фон без * спрайтов, а если писать банком без тени, копия страницы-приёмника * останется старой и heal начнёт восстанавливать прошлую картинку. * * VFLIP отражает область ВНУТРИ СЕБЯ: строка area->y + i уходит в строку * area->y + area->h - 1 - i. Горизонтального зеркала здесь нет и не * будет — accel копирует блок только вперёд, побайтовый реверс стоил бы * 320 burst'ов на строку вместо двух (для персонажей зеркало делается * раскладкой спрайта, см. gfx_blit_cols). * * Ширина режется на burst'ы ≤ 255 байт (лимит accel-блока; 256 у нынешних * leaf'ов даёт мусор на втором проходе — тот же TODO, что в gfx_scroll_h). * Высоту и DI/EI-банды по 16 строк leaf делает сам. */ #include "../include/gfx.h" #include "../include/sprite.h" #include "../_bgi.h" void gfx_copy_page(const gfx_rect_t *area, uint8_t mode) { uint8_t saved = gfx_get_bank(); uint16_t w = area->w; uint8_t h = (uint8_t)area->h; /* 256 => 0 — конвенция accel */ uint16_t src = _gfx_addr_shadow_base + (uint16_t)area->x; uint16_t dst = _gfx_addr_base + (uint16_t)area->x; uint8_t y0 = (uint8_t)area->y; /* Port_Y приёмника: при перевороте начинаем с НИЖНЕЙ строки области и * идём вверх; при прямой копии — та же строка, что у источника. */ uint8_t y1 = (mode == GFX_COPY_VFLIP) ? (uint8_t)(area->y + area->h - 1) : y0; if (!w || !area->h) return; gfx_set_bank(GFX_BANK_NORMAL); _bgi_begin(); while (w) { uint8_t cw = (w > 255) ? 255 : (uint8_t)w; if (mode == GFX_COPY_VFLIP) _bgi_flip_rows_raw(src, dst, cw, h, y0, y1); else _bgi_scroll_rows_raw(src, dst, cw, h, y0); src += cw; dst += cw; w -= cw; } _bgi_end(); gfx_set_bank(saved); }