Magnets stretching
Alone Coder
Расскажу про эффект в гритсах демы
The Board II, основного названия которого
я нигде не нашёл, то ли он "стретч", то ли
"магниты". Пусть будут "магниты".
Идея у него такая:есть две летающих то─
чки со своими системами полярных коорди─
нат:U1, V1 и U2, V2 (может быть и U3, V3,
если точек не две, а три); для каждого эк─
ранного пикселя(x,y) находим координаты в
каждой из систем полярных координат, соот─
ветствующие координаты складываем(U1+U2,
V1+V2), читаем по ним пиксель из текстуры
и выводим на экран.
Казалось бы, просто,но обычно на Speccy
этот эффект был очень медленным, даже в
низком разрешении. А я решил сделать его
чанками 2x2.
Дема писалась под ATM Turbo 2+, но пос─
кольку компомашина на том пати была ZX Evo
с прошивкой baseconf (основная прошивка
этого компьютера-конструктора реализует
ATM Turbo 2+ на 14 MHz,наряду с тремя -
тогда одной - другими известными моделями
Спектрума и одной виртуальной под названи─
ем "ATMЗ", которую сейчас разводит Zorel),
то был стимул даже попытаться сделать этот
эффект фреймовым на компомашине, с обычной
автоподстройкой демы под скорость машины.
У меня уже были данные по скорости выпол─
нения команд там: основная идея в том, что
машинный цикл с чтением округляется до чё─
тного такта,если ячейка не считана заранее
в 16-битный буфер; буфер всегда читается с
чётного адреса памяти. Но поскольку дли─
тельности команд в таких "турботактах"
непривычны и нестандартны,буду писать при─
меры с обычными тактами и считать, что в
кадре их примерно 220000 (примерно 100000
на ATM Turbo 2/2+ @ 7 MHz ). Конечно, это
число зависит от кода, но в любом случае,
если бы расчёты не сходились, всегда была
возможность уменьшить окошко.И всегда надо
помнить, что мы пишем под ретромашину,а не
под какую-то прошивку компьютера-конструк─
тора или ещё какой эмулятор с "новыми воз─
можностями" (которые реально нельзя под─
ключить к Спектруму). Ибо какой смысл ухо─
дить со Спектрума на липовые "новые возмо─
жности на базе Спектрума", если кругом по─
лно настоящих платформ с приличными людь─
ми? Смысл только для тех, кому лень писать
под настоящее ретро, а раскрутиться хочет─
ся (они даже объединяются для восхваления
друг друга и травли тех,кто не любит фейки
и прочее пускание пыли в глаза).
Напомню, какие экранные режимы у нас
есть на ATM Turbo 2/2+ и его современных
реализациях:
-6912;
-"EGA" 320x200, 16 цветов на точку.В
каждом байте 2 пикселя, которые кодируются
как атрибуты на 6912. Экран в памяти раз─
делён на 4 слоя по 8000 байт, которые че─
редуются через каждые 2 пикселя по горизо─
нтали. Внутри слоя адрес растёт линейно.
Слои лежат в разных страницах и половинках
страниц;
-мультиколор 640x200, hires. Пиксели
лежат в одной странице, атрибуты в другой.
Причём как пиксели, так и атрибуты разде─
лены на 2 чередующихся слоя каждый;
-текстмод 80x25.
Режимы Timex Sinclair 2068 не поддержа─
ны.
Первая идея, конечно,была с использова─
нием чанков и процедуры c2p. Но легко ви─
деть, что результат не достигается даже
близко: c2p через pop hl:ldd:ld a,(hl):
ld (bc),a, скажем, в окне320x96, займёт
40*160*48 = 307200 тактов - не считая са─
мого эффекта, который явно будет не с дву─
мя командами.
Тем более, зачем нам c2p,если можно вы─
водить только каждую вторую строчку (про─
межуточные строчки отдать под надписи) -
то есть по сути гонять целые байты из тек─
стуры прямо в экран?
После этих рассуждений эффект виделся
таким (на EGA экране):
Этап 1: складываем координаты по двум
таблицам полярных координат:
ld a,(de):inc e ;U1
add a,(hl):inc l ;U2
push af
:33 t/чанк на одну координату
ld a,(de):inc e ;V1
add a,(hl):inc l ;V2
ld c,N:ld (bc),a
:36 t/чанк на вторую координату
(в сумме 69 t/чанк)
Этап 2: читаем пиксель из текстуры и
выводим его на экран:
pop hl ;координаты в текстуре
ldi ;байт из текстуры пишем в экран
:26 t/чанк
Процедуры простые, типовые, но...расто─
чительно, не так ли?
Поэтому я прикинул, можем ли мы объеди─
нить расчёт координат и чтение текстуры.
Это получится сделать, если таблица поляр─
ных координат для одной из точек будет
вбита прямо в процедуру:
pop bc ;UV1=полярные коорд-ты для точки1
ld hl,NN ;UV2=полярные коорд-ты для точки2
add hl,bc ;адрес в текстуре
set 7,h ;нельзя занять все 64K текстурой!
ldi ;байт из текстуры
:55 t/чанк
За каждый проход мы выводим только один
слой экрана из 4, то есть всё время пере─
скакиваем через 3 чанка (один слой содер─
жит пиксели0,1,8,9.., второй - пиксели
2,3,10,11.., третий - пиксели4,5,12,13..,
четвёртый...ну,вы поняли).Такие вот хитрые
экраны на настоящем ретро - не для ламе─
ров :)
Легко видеть, что попытка выводить на
все слои сразу ведёт к проигрышу тактов,
даже если писать так:
ld a,(de):inc e ;U1
add a,(hl):inc l ;U2
ld c,a
ld a,(de):inc e ;V1
add a,(hl):inc l ;V2
ld b,a
ld a,(bc)
ld (NN),a ;чередуем слои
:72 t/чанк -
и это ещё без ограничения адресного прост─
ранства текстуры!
Перевод эффекта в мультиколор (2 чанка
в байте) тоже кажется проигрышем:
pop bc ;UV1
ld a,(de):inc e ;U2
add a,c
ld l,a ;U
ld a,(de):inc e ;V2
add a,b
ld h,a ;V
ld c/b,(hl) ;байт из текстуры
1/2*ld a,(bc):ld (NN),a
:65 t/чанк
(без ограничения адресного пространства
текстуры)
И пока даже непонятно, в каких окнах
памяти что будет лежать (таблица полярных
координат, текстура,код и две страницы эк─
рана или одна для мультиколора).
Сидим, грустим.
Очевидно, нужна смена алгоритма. Какая?
Попробуем текстуру 16x16 (в одном байте
обе координаты -%VVVVUUUU ):
1/2*pop bc ;UV1 (читаем по 2 записи сразу)
ld a,(de):inc e ;UV2
add a,c/b ;переполнение по мл. координате!
ld l,a ;координаты в текстуре
ld a,(hl)
ld (NN),a ;чередуем слои
:51 t/чанк
Или для мультиколора:
pop bc ;UV1 (читаем по две записи сразу)
ld a,(de):inc e ;UV2 левая
add a,c ;переполнение по мл. координате!
ld c,a ;координаты в текстуре, левая
ld a,(de):inc e ;UV2 правая
add a,b ;переполнение по мл. координате!
ld l,a ;координаты в текстуре, правая
ld b,N
ld a,(bc) ;%LOLLLOO00
or (hl) ;%0R0OORRR
ld (NN),a ;чередуем слои
:82 t/2 чанка = 41 t/чанк
Выигрыш более чем в 2 раза по сравнению
с первоначальным вариантом! Но в окне
320x96 пока315000 тактов - никак не лезет
во фрейм. Можно ли выиграть ещё?
Можно, и даже существенно!
Пусть точки движутся зеркально относи─
тельно центра экрана.Тогда нижняя половина
экрана - копия верхней с поворотом на 180
градусов. Такой переворот гораздо быстрее,
чем вывод эффекта:
1/2*pop de
ld (hl),d/e:dec l
:16 t/чанк
Или для мультиколора (тут уже нужна та─
блица переворота байтов):
1/2*pop bc ;b,c!=0
ld l,c/b
ldd
:25 t/2 чанка = 12.5 t/чанк
С таблицей оказалось быстрее, чем без
таблицы :)
Кроме того,мы можем переворачивать пря─
мо во время вывода!
1/2*pop bc ;UV1 (читаем по 2 записи сразу)
ld a,(de):inc e ;UV2
add a,c/b ;переполнение по мл. координате!
ld l,a ;координаты в текстуре
ld a,(hl)
ld (NN),a ;эффект
ld (NN),a ;отражение
:64 t/2 чанка = 32 t/чанк
Или для мультиколора:
pop bc ;UV1 (читаем по 2 записи сразу)
ld a,(de):inc e ;UV2, левый чанк
add a,c ;переполнение по мл. координате!
ld c,a ;координаты в текстуре, левый чанк
ld a,(de):inc e ;UV2, правый чанк
add a,b ;переполнение по мл. координате!
ld l,a ;координаты в текстуре, правый чанк
ld b,h
ld a,(bc) ;%LOLLLOO00
inc h
or (hl) ;%0R0OORRR
ld (NN),a ;эффект
inc b
ld a,(bc) ;%0L0OOLLL
dec h
or (hl) ;%RORRROO0
ld (NN),a ;отражение
:110 t/4 чанка - 27.5 t/чанк
Ещё одна проблема - на стыке эффекта и
отражения может получиться разрыв.В первую
очередь из-за того,что постоянно возникает
переполнение по младшей координате.Его мо─
жно избежать,если текстура будет не16x16,
а16x8. Тогда байты будут%VVVVOUUU, и при
сложении переполнение уйдёт в бит нуля,ко─
торый не будет ни на что влиять.
Но есть способ лучше - рисовать чётные
строки эффекта на всю высоту экрана, а не─
чётные получать отражением. Тогда разрывы
не будут видны.
Это позволяет в мультиколоре с тексту─
рой8x8 реализовать ещё более хитрый метод
- чтение из текстуры двух чанков сразу!
pop de
ld a,e
add a,(hl):dec l ;OOvvvuuu + OOvvvuuu
; = 0?vvvuuu
ld e,a ;координаты в текстуре, левый чанк
ld a,d
add a,(hl):dec l ;OOvvvuuu + OOvvvuuu
; = 0?vvvuuu
ld d,a ;координаты в текстуре, правый чанк
ld a,(de) ;два цвета
exx
ld (bc),a ;эффект
ld l,a ;h=tMIRROR/256
ldi ;отражение ;c!=0
exx
:90 t/4 чанка = 22.5 t/чанк
Конечно, это в теории. На практике надо
вписаться в окна памяти.
Экран и таблица полярных координат пе─
реключаются (для каждого слоя экрана -
своя таблица).Код и текстура - нет (в этом
коде нет адресов,так что он уже не требует
распихивания по куче страниц). Но с 32-ки─
лобайтной текстурой некуда класть код.
Поэтому текстуру придётся ужать в одно
окно (для этого надо добавить and c перед
ld d,a, приc=#3f ). Ещё одно окно займёт
экран (переключаемый). Ещё одно - таблица
полярных координат (переключаемая). А ос─
тавшееся окно займёт код.
Таблица полярных координат поместится в
одно окно, если не будет выравнена по 256
байт, например, с картой224x144. Для это─
гоdec l придётся заменить на dec hl. Есть
способ заменить только один из них - уга─
даете как? Правильно, для каждой чётности
X-координаты - своя таблица полярных коор─
динат :)
Так что финальный вариант эффекта та─
кой:
pop de
ld a,e
add a,(hl):dec l ;OOvvvuuu + OOvvvuuu
; = 0?vvvuuu
ld e,a ;координаты в текстуре, левый чанк
ld a,d
add a,(hl):dec hl ;OvvvOuuu + OvvvOuuu
; = ?nnn?nnn
and c ;#3f
ld d,a ;координаты в текстуре, правый чанк
ld a,(de) ;два цвета
exx
ld (bc),a ;эффект
ld l,a ;h=tMIRROR/256
ldi ;отражение ;c!=0
exx
:96 t/4 чанка = 24 t/чанк
Обвязка:
DRLOOPO
dup wid/4 ;=40
<эффект>
edup
org $-1
ld hl,-40*4+(wid/4)
add hl,bc
ld b,h
ld c,l
ld hl,+40*4-(wid/4)
add hl,de
ex de,hl
ld h,tMIRROR/256
exx
dec b
jp nz,DRLOOPO
Осталось написать генератор таблиц и
текстур,добавить показ титров и скриптова─
ние, и эффект готов!
Other articles: