L9-INVERT: зеркальный слой фона + вход в комнату в банк 8

II.3: pop_upside проведён в единственную точку тайлового слоя (pop_blit_b /
blit_b_clip): позиция через FLIP_TOP, блит — vflip-двойник.  Этим зеркалятся
полная отрисовка комнаты, точечные редрои, trob-анимации, fore-слой и кладка.
В клипованном пути обрезка сверху экрана съедает нижние строки источника,
поэтому кусок пересчитывается как sy' = h - sy - dh.

MEM-COLD2 п.1: enter_room_side/enter_room — в банк 8 (куча 450 -> 1231 Б).
Рабочие массивы комнаты остались в _DATA, в банк уехал только код.

Проверено в MAME (уровень 9, чит U): комната перевёрнута целиком, пол
вверху, дверь и кладка вверх ногами.  tests-host 6/6, size-check OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 17:43:22 +03:00
parent 5c015739fa
commit 7c1ded340c
5 changed files with 228 additions and 161 deletions
+33 -5
View File
@@ -10,7 +10,8 @@
#include <graphics.h>
#include <gfx.h>
#include <sprite.h>
#include "pop_bg.h" /* POP_YOFF */
#include "pop_bg.h" /* POP_YOFF, POP_PLAYFIELD_H */
#include "pop_map.h" /* pop_upside — переворот (зелье инверсии) */
#include "pop_cdraw.h" /* POP_CD_TOUCH — фон тронут, персонажей перерисовать */
#include "pop_tile.h"
#include "pop_level.h" /* pop_doorlink2 — подстановка нажатой кнопки */
@@ -262,6 +263,12 @@ void pop_cd_clear(uint8_t p)
* платили и блиты БЕЗ клипа (`ld -n(ix)` = 19 тактов номинала, у нас ~46).
* А блитов без клипа большинство: весь фон вне fore-прохода — факелы, зелья,
* перерисовка тайлов — идёт с pop_t_fclip_on == 0. */
/* Экранный y при ПЕРЕВОРОТЕ (зелье инверсии): поле отражается внутри себя,
* борта не трогаются. Одна формула на весь слой фона — если её продублируют
* где-то ещё, получим двойной переворот (см. l9_invert_plan.md §II.2:
* зеркалит ТОЛЬКО вызывающий, у примитивов семантика не меняется). */
#define FLIP_TOP(top, h) (2 * POP_YOFF + POP_PLAYFIELD_H - (top) - (int)(h))
static void blit_b_clip(const uint8_t *img, int x, int top, int w, int h)
{
int dx = x, dy = top, dw = w, dh = h, sx = 0, sy = 0;
@@ -275,6 +282,20 @@ static void blit_b_clip(const uint8_t *img, int x, int top, int w, int h)
if (dy + dh > pop_t_fclip_y1) dh = pop_t_fclip_y1 - dy;
}
if (dw <= 0 || dh <= 0) return;
/* ПЕРЕВОРОТ: экранная строка (dy+i) берёт источник (h-1-i), поэтому
* обрезка СВЕРХУ экрана съедает НИЖНИЕ строки источника. В терминах
* куска источника это sy' = h - sy - dh (при обрезке только сверху даёт
* 0, при обрезке только снизу — верхний край). */
if (pop_upside) {
int fsy = h - sy - dh;
if (fsy < 0) fsy = 0;
if (dx >= 0 && dy >= 0 && dw < 256 && dh < 256 &&
dx + dw <= 320 && dy + dh <= 256 && w < 256)
gfx_blit_part_noclip_vflip(dx, dy, img, (uint8_t)sx, (uint8_t)fsy,
(uint8_t)dw, (uint8_t)dh);
else
gfx_blit_part_vflip(dx, dy, img, sx, fsy, dw, dh);
} else
if (dx >= 0 && dy >= 0 && dw < 256 && dh < 256 &&
dx + dw <= 320 && dy + dh <= 256 && w < 256) {
if (sx == 0 && sy == 0 && dw == w && dh == h)
@@ -313,6 +334,10 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
top = ybottom - (int)h + 1 + POP_YOFF; /* +YOFF: центрирование */
/* Переворот применяем ЗДЕСЬ, до клипа: дальше вся геометрия (окно
* fore-слоя, полоса у потолка, отсев по экрану) считается уже в
* экранных координатах результата. */
if (pop_upside) top = FLIP_TOP(top, h);
if (w && h) {
if (!pop_t_fclip_on && !pop_t_clip_top) {
/* БЫСТРЫЙ путь: клипа нет вовсе. Так идут все блиты фона вне
@@ -321,10 +346,13 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
* платит за клип/16-бит/split, а не за пиксели). W3-скобку
* ставит сама libbgi: из кода с --w3 её вызывать нельзя. */
if (x >= 0 && top >= 0 && w < 256 && h < 256 &&
x + (int)w <= 320 && top + (int)h <= 256)
gfx_blit_noclip(x, top, img);
else
gfx_blit_part(x, top, img, 0, 0, (int)w, (int)h);
x + (int)w <= 320 && top + (int)h <= 256) {
if (pop_upside) gfx_blit_noclip_vflip(x, top, img);
else gfx_blit_noclip(x, top, img);
} else {
if (pop_upside) gfx_blit_part_vflip(x, top, img, 0, 0, (int)w, (int)h);
else gfx_blit_part(x, top, img, 0, 0, (int)w, (int)h);
}
pop_cd_touch(x, top, (int)w, (int)h);
} else {
blit_b_clip(img, x, top, (int)w, (int)h);