/* * _gfx_blit_full_op — bracket-free ядро блита под-прямоугольника картинки * getimage-формата ЛОГИЧЕСКОЙ ОПЕРАЦИЕЙ (приёмник = приёмник * источник). Полный близнец _gfx_blit_full: тот же клип по экрану, та же * нарезка на полосы ≤256 байт, БЕЗ _bgi_begin/_bgi_end и БЕЗ смены банка * (вызывающий обязан замапить W3 и выставить банк). Разница одна — вызов * op-ядра _bgi_blit_rows_op_raw вместо копирующего. * * ПОЧЕМУ ОТДЕЛЬНОЕ ТЕЛО, а не флаг в _gfx_blit_full. Копирующий путь — * горячий (спрайтовый движок гоняет его в batch-цикле); ветка «а не * операция ли?» тянула бы op-ядро в любую программу с блитом (~+170 Б * _CODE при нулевой пользе). Клип-математика дублируется сознательно — * правки вносить в ОБА файла (близнец: common/_gfx_blit_full.c). * * ---- ПРОЗРАЧНОСТЬ (главное отличие от копии) ---------------------- * Аппаратная прозрачность (банк 0x58/0x5C: байт #FF не пишется) смотрит на * РЕЗУЛЬТАТ операции, а не на источник, поэтому достаётся даром не всем: * GFX_OP_AND — прозрачный #FF нейтрален сам по себе (#FF & bg = bg), * банк не важен; * GFX_OP_OR — #FF | bg = #FF, и запись такого байта подавляется банком * 0x58/0x5C: обычный атлас годится КАК ЕСТЬ. Оговорка: * подавится и «настоящий» результат, случайно равный #FF; * GFX_OP_XOR — с прозрачностью #FF НЕ РАБОТАЕТ: #FF ^ bg = ~bg, то есть * инверсия фона по всему прямоугольнику картинки. Источник * для XOR обязан хранить прозрачный пиксель как 0x00 — * нейтральный элемент и для XOR, и для OR (так же, как в * DOS-оригиналах, где прозрачный индекс = 0). * Замаскировать #FF внутри операции нельзя в принципе: побитовые AND/OR/XOR * не умеют «выбрать по условию», а #FF — нейтраль только для AND. * * ---- ЧТО ЧИТАЕТ ОПЕРАЦИЯ ------------------------------------------ * Чтение страниц #50..#5F всегда отдаёт ОЗУ-копию экрана * (memory/sprinter_vram_transparency), поэтому при банке 0x54/0x5C («не * писать в копию») операция совмещается с ЧИСТЫМ ФОНОМ, а не с тем, что * уже нарисовано поверх. Нужен результат поверх нарисованного — рисовать * банком GFX_BANK_NORMAL (0x50), где копия и видео-ОЗУ совпадают; платой * будет потеря дарового heal из копии. * * Цена: три accel-burst'а на строку вместо двух (+50% времени accel); * подготовка/клип — как у копии. */ #include "../_bgi.h" void _gfx_blit_full_op(int x, int y, const void *img, int sx, int sy, int w, int h, uint8_t op) { const uint8_t *p = (const uint8_t *)img; const uint8_t *src; uint16_t dst; int img_w; /* img_w — ПОЛНАЯ ширина картинки/ленты из заголовка getimage * (p[0]=lo, p[1]=hi) = шаг между строками источника (sstride). */ img_w = p[0] | (p[1] << 8); /* Клип по экрану — только если хоть один край вылезает. */ if (x < 0 || y < 0 || x + w > _bgi_maxx + 1 || y + h > _bgi_maxy + 1) { if (x < 0) { sx -= x; w += x; x = 0; } if (y < 0) { sy -= y; h += y; y = 0; } if (x + w > _bgi_maxx + 1) w = _bgi_maxx + 1 - x; if (y + h > _bgi_maxy + 1) h = _bgi_maxy + 1 - y; if (w <= 0 || h <= 0) return; } src = p + 4 + sx; if (sy) src += (uint16_t)sy * (uint16_t)img_w; dst = _gfx_addr_base + x; while (w > 256) { _bgi_blit_rows_op_raw(src, (uint8_t *)dst, 0 /* =256 */, (uint8_t)h, img_w, (uint8_t)y, op); src += 256; dst += 256; w -= 256; } _bgi_blit_rows_op_raw(src, (uint8_t *)dst, (uint8_t)w, (uint8_t)h, img_w, (uint8_t)y, op); }