На последнем собрании true zx'еров, мы все много общались. Ваня Пирог и Вал просили меня объяснить, как же был сделан эффект "XOR-CYRCLES" в SYNCHRONIZATION. Но я как не шуршал мозгами замаринованные в коньяке, так и не смог вспомнить.
Речь идёт вот про этот эффект https://youtu.be/e4gy3lJ3ZU4?t=382
Итак, как же оно работает ... Всё очень просто, но нужно вчитаться ... Итак есть текстовый режим и прерывания на каждую строчку, начиная с минус один от первой отображаемой линии.
1. Вначале прерывание, которое происходит 240 раз. Оно нужно, что бы в первую очередь, задать новую отображаемую линию для текстового режима, и во вторую очередь выпендриться и покрасить бордюр в новый цвет. Но главная фишка именно в обновлении отображение новой линии. У меня есть зарезервированные страницы с какого-то там места, выделенного автоматически под именем VTX_PAGE. В VTX_PAGE лежит экранная область отображаемая TSLDac'ом, но линейно. То есть вначале отобразятся первый 64 символа, потом вторые, ну и так 240 раз ... В итоге у нас получается некая видео-область размером в 240*64, что является 8-ми tslстраниц. Нужно помнить, что у Вала каждая новая строчка пересчитывается с учётом смещения по Y, в итоге каждое прерывание обновляет новое смещение по Y и высчитывает новый адрес страницы для VideoPage. Выглядит это так:
- Code: Select all
INPEx2 LD HL,0
LD BC,8
ADD HL,BC
LD (INPEx2+1),HL
LD BC,TSL.GYOffsL
OUT (C),L
INC B
OUT (C),H
LD B,HIGH(TSL.Vpage)
LD A,H
AND 00000110B
ADD A,VTX_PAGE
OUT (C),A
2. Далее подготовка графики для текста. В предыдущем пункте решена проблема с отображением, теперь когда у нас есть линейное отображение памяти в пикселях, можно заниматься магией. Итак, у нас высвечивается 480 по 8 пикселей, код текста с адреса VTX_PAGE+64*LINE. Реальных, а точнее привычных нам пикселей не 8 а 4, по скольку текст в двое плотнее стандартного графического режима. Теперь перед всем этим эффектом, один раз заполняем графику текста, так что бы код буквы соответствовал XORу верхней и нижней тетрады кода символа.. То есть например код отображаемого символа в бинари такой "10010011" это значит что я хочу сделать "1001" XOR "0011" = "1010". Отлично, теперь символ с кодом "10010011", заполняем графикой восемь раз "11001100", что равно "1010". Однако, сделаем эффект более интересный, где пиксели будут преобладать над пустотой, тогда появится "жирность". Так что сегенируем табличку ITEG_TBL из 16-ти значений утолщённых пикселей. Графика текста складывается в страницу (VTX_PAGE+1). Генератор графики получается таким:
- Code: Select all
InitTextGFX:
LD A,VTX_PAGE+1
CALL IORQTS.RAMPage3
LD HL,49152
LD BC,0000H
LD D,HIGH(ITEG_TBL)
ITEGx1 LD A,C
RRCA
RRCA
RRCA
RRCA
XOR C
AND 00001111B
ADD A,LOW(ITEG_TBL)
LD E,A
LD A,(DE)
.8
LD (HL),A
INC L
..
ORG $-1
INC HL
INC C
DJNZ ITEGx1
RET
ALIGN 16
ITEG_TBL ; 0 0 0 0
DB 00000000B
DB 00000011B
DB 00001110B
DB 00001111B
DB 00111000B
DB 00111111B
DB 00111110B
DB 00111111B
DB 11100000B
DB 11110111B
DB 11101110B
DB 11101111B
DB 11111000B
DB 11111011B
DB 11111110B
DB 11111111B
3. Далее подготовка кругов. Я не буду расписывать сам генератор, но смысл прост, на нужно сгенерировать 8-мь гигантских экранов размером 128х512 байт, где графика будет хранить в верхней тетраде, и ещё 8-мь экранов точно таких же, где графика будет в нижней тетраде. Получится что нужно 128*512*8*2 = 1 мегабайт памяти. Его и заполняем графикой кругов. Вот пока вылетает череп с шариками вместо глаз, это и происходит на заднем плане ...
4. Далее DMA копирование, которое будет формировать изображение. Тут всё просто ... Вначале нужно скопировать с помощью DMA, с флагом RAM_RAM, из первой области гигантского экрана в VTX_PAGE видео-области. Следующим шагом скопировать в то же самое место VTX_PAGE видео-области из второй области гигантского экрана но с флагом BLT_RAM. Получается что вы скрестите верхние и нижние тетрады двух гигантских экранов с кругами в видео-области. И по-скольку графика каждого кода символа уже раскранчена XOR'ом, у вас получается аппарат, который сам за вас XOR'ит. Ваша задача только задавать DMA аппарату, что, куда и откуда копировать, ну и процессором ничего не делать. Вот выдержка процедур, которые копируют и ждут:
- Code: Select all
CALL INTDMA0
CALL IORQTS.DMA_WAIT
CALL INTDMA4
CALL ShowBallA
CALL IORQTS.DMA_WAIT
CALL INTDMA1
CALL ShowBallB
CALL IORQTS.DMA_WAIT
CALL INTDMA5
CALL IORQTS.DMA_WAIT
CALL INTDMA2
CALL IORQTS.DMA_WAIT
CALL INTDMA6
CALL MUSIC.PLAYSTEP
CALL IORQTS.DMA_WAIT
CALL INTDMA3
CALL IORQTS.DMA_WAIT
CALL INTDMA7
RET
Если присмотритесь, то пока DMA что там копирует я не сильно парясь обновляю координаты шариков - "ShowBallA" и "ShowBallB", где-то в конце ещё и музыку играю "MUSIC.PLAYSTEP".
А теперь похвастаюсь своим MASONом. Сверху виден пример, что в середине прерывания я вызываю "MUSIC.PLAYSTEP". Может показаться, что в каждом эффекте нужно вызывать руками эту процедуру? Это не так! В этом и прелесть этого плеера. Каждое прерывание происходит вот такое:
- Code: Select all
CALL MUSIC.OUT
CALL SUPER_PUPER_EFFECT
LD A,MUSIC.PAGE
CALL IORQ.MUSIC_PAGE_SWITCH_A
CALL Mas_LOA
CALL Z,MUSIC.PLAY
Это стандартный аппарат который крутит всю дему или игру. Процедура SUPER_PUPER_EFFECT это ваши действия, где вы показываете графику или что-то ещё. В этой процедуре можно вызвать процедуру "MUSIC.PLAYSTEP", которая за вас переключит страницу, проиграет музыку, и вернёт страницу назад. Далее, выйдя из процедуры вашего эффекта, исполнится процедура "Mas_LOA", которая сама подготовит буфер для отправки на AY и проверит нужно-ли плееру новые данные на следующее прерывание выставляя флаг ZF, что даёт сигнал для вот этой команды "CALL Z,MUSIC.PLAY". Таким образом вы в прерывании можете вызвать 10-ть раз процедуру "MUSIC.PLAYSTEP", и автоматически на 10-ть прерываний вперёд сохранятся данные для AY'ка. Догадайтесь сами какие возможности у вас появляются. Кстати, можно вызвать процедуру "MUSIC.PLAY0", и тогда в буфер упадёт только данные канала "А", ну а если вызвать "MUSIC.PLAY1", то данные канала "В"! Можете делать это в любой момент, когда вам это удобно и главное, все эти вызовы стабильны в прерывании. То есть всегда будут занимать одно и то же количество тактов, при любых данных музыки.
Я не знал в какую рубрику отнести этот топик, поэтому если это больше подходить для, например, "демо", то прошу перебросить его "туды", или ещё "куды".