Фреймовость в режиме 16 color — Abzac


PeriodicalsAbzac2009 No. 32 → Фреймовость в режиме 16 color

Фреймовость в режиме 16 color

Продолжение статьи, опуб­ликованной в ACNews #55.

* * *

Есть возможность писать на NGS (NeoGS) фреймовые игры в режиме «цвет на точку». Идея в том, что NGS генерирует после­довательность команд для ZX, а ZX их исполняет через DMA. Один экран светится на экране, другой в это время строится. Для этого DMA должна поддержи­вать возможность исполнять ко­манды из памяти NGS. Команды такого типа:

LD HL,...

LD (HL),...

INC L

или такого:

LD A,...

LD (...),A

или же такого:

LD HL,...

LD (...),HL

Можно использовать и ко­манды CALL, например, для пе­реключения страниц с экранами.

Код можно выполнять только подряд, поскольку в FPGA NGS заведены не все адресные сигна­лы ZX (только A0-A7, A14, A15), поэтому она не знает, какой ад­рес хочет прочитать ZX. Она отдаёт байты подряд с автоин­крементом адреса. Причём счи­тываемый байт подготавлива­ется заранее, что минимизирует вайты процессору NGS.

На прозрачных областях спрайтов код генерировать не надо. 30 спрайтов 16x16 при по­следнем варианте вполне умеща­ются во фрейм. При этом после­довательность команд занимает чуть менее 16K. Если понадобит­ся больше 16K, то можно разби­вать код на страницы по слоям экрана (4 слоя) или поспрайто­во, или (если выводим большую картинку разом) построчно/по­столбцово.

Чтобы генерировать такие команды для вывода/стирания спрайтов, NGS должен хранить копию текущего игрового экрана (точнее, обеих экранных облас­тей). Есть несколько различных методов генерации такого кода:


Метод 1

Работаем со спрайтами на NGS как обычно на ZX, а по­том сравниваем текущий и пре­дыдущий (точнее, предыдущее состояние текущей экранной области из двух) экраны и гене­рируем на их основе код. С точ­ки зрения ZX этот метод наибо­лее эффективен (не требуется несколько раз перерисовывать байты спрайтов, которые стоят на месте или перекрывают друг друга). Но NGS не потянет. Срав­нение требует 66 тактов на сло­во (на пустых словах), итого, бо­лее 800000 тактов на весь экран. На NGS у нас в лучшем случае 491520 тактов.


Метод 2

Строим код непосредствен­но во время вывода и стирания спрайтов. Проблема в том, что в главном цикле вывода спрайтов использовано слишком много регистров - а это значит тормоз:

1. Адрес графики спрайта.

2. Адрес на экранном буфе­ре NGS.

3. Адрес в буфере заднего плана.

4. Адрес на экране ZX.

5. Адрес генерируемого кода.

Можно 2 и 4 сделать одина­ковыми. Можно убрать 3, если фон перерисовывается в NGS целиком (258048 тактов – не ре­комендую; впрочем, можно сде­лать быстрый аналог LDIR внут­ри FPGA).

Можно убрать 1, если сге­нерировать процедуры для ка­ждого спрайта (точнее, каждой фазы). В этом случае можно во­обще пропускать прозрачные участки спрайтов.


Метод 3

Во время вывода спрайтов устанавливаем байты в байтма­ске экрана, а потом по ней стро­им выводилку, как в первом ме­тоде. В этом случае будет от 27 (INC L: LD A,(HL): INC L: OR (HL): RET NZ) тактов на сло­во (на пустых словах), то есть 331776 тактов на весь экран. Это неприемлемо. Если же вме­сто байтмаски использовать битмаску, то можно сравнивать быстрее, но процедура вывода спрайтов усложнится. Так что метод заслуживает обсужде­ния. При этом методе не обяза­тельно сохранять картинку под выводимыми спрайтами, так как её можно восстанавливать по байтмаске/битмаске и копии фона. Это позволит сэкономить регистры и получить более ско­ростной вывод спрайтов.


Метод 4

Поскольку во время вывода спрайтов мы строим буфер для их восстановления, то на осно­ве этого буфера можно строить нужный нам код (отдельной про­цедурой).

При аккуратном програм­мировании можно достичь этих самых 30 спрайтов на экране. Именно при аккуратном, т.к., на­пример, в PANG 16C было 130 тактов на байт спрайта, вклю­чая обработку списков объектов (но не интеллект!). Разумеется, чем спрайты меньше, тем мень­ше времени они занимают вооб­ще, но больше в расчёте на байт. Спрайты типа разлетающихся пикселей (если их сотни) надо обрабатывать отдельными опти­мизированными процедурами.

Аппаратный скролл в на­стоящий момент доступен толь­ко по вертикали: на АТМ Turbo 2+ по умолчанию, на Pentagon 1024 SL 2.2 при новой про­шивке от DDp (http://zx.pk.ru/showthread.php?p=205230). Он делал и горизонтальный, но оба не умещаются в одну прошивку. Приехавшие при скроллинге ли­нии надо перерисовывать теми же методами: NGS генерирует код, ZX его исполняет. Пробле­ма в том, что игровую панельку придётся перерисовывать на ка­ждом кадре.

Игры, где движущегося фона не очень много (типа Super Mario) можно писать и без аппаратно­го скролла. Графику в памяти ZX хранить не требуется - она вся бу­дет внутри NGS.