Scroll'ы бывают разные


изображение из демо New Year Demo(https://zxaaa.net/view_demo.php?id=11161)

История в продолжение записей в блоге, в которых уже были описаны
способы визуализации простого эффекта.

В начале января в почту прилетает письмо от ААА с файлами и описанием
демо: музыка, картинка, .GIF и ссылка на демо с описанием: "выдери скролл,
поменяй параметры и вставь в демо".

Выдрать код - это моветон, к тому же бегущая строка в демо использует
двойной экран, поэтому с анимацией кадра вряд ли подружится. Поэтому
я лучше поломаю голову и сделаю аналогичный скролл в один фрейм.

Раздумья были долгими, описание выйдет быстрее.

для скролла отведено 8 байт или 8*8=64 пикселя. Но нужно учитывать
размер букв 8х8 пикселей, тогда буквы не вылетят за край экрана.
получается амплитуда 64-8=56 пикселей. Синус - функция периодическая
с диапазоном значений [-1..1]. Поэтому генерируется таблица 256 байт:
(PureBasic)

CreateFile(0,"zaasin.data")

For i=0 To 255
  a.a=Int(28+28*Sin(i*#PI/128))
  WriteAsciiCharacter(0,a)
Next i

CloseFile(0)



Теперь вывод на экран. Как он будет реализован? Набираю код:

zu:
    ei:halt
    ld a,0:out ($FE),a
    ld (back_sp+1),sp
 dup 192
    ld sp,0
    pop hl:ld (0),hl
    pop hl:ld (2),hl
    pop hl:ld (4),hl
    pop hl:ld (6),hl
edup
back_sp: ld sp,0
    ld a,7:out ($FE),a
    jp zu


Здесь скорость выполнения кода реализована по старинке,
видно,  что вывод на экран оставит времени для остальных
действий демо - анимация картинки и воспроизведение музыки.

Куда разместить данные, которые будут скопированы
с помощью стека?

Высота экрана 192 пикселя или 64*3 - тут решение напрашивается
само собой. Данные для анимации хранятся в странице 0, я использую
страницу 1, которая адресована $C000-$FFFF.
Получается, что:
$C000-$C008 - линия 0
$C100-$C108 - линия 1
...
$FF00-$FF08 - линия 63
Для второй половины выйдет:
$C008-$C010 - линия 64
$C108-$C118 - линия 65
...
$FF08-$FF10 - линия 127

и для линий 128-192 можно добавить 8 байт.
Эти данные расположены по линиям, например $C000-$C018.
Такая организация позволит быстро очищать буквы для скролла.

Подготовка формирования процедуры выглядела так:

;form output
    ld hl,ou
    ld de,$4018
    ld bc,$C000
f1:
    ld (hl),$31:inc hl
    ld (hl),c:inc hl
    ld (hl),b:inc hl
    push de
 dup 4
    ld (hl),$E1:inc hl
    ld (hl),$22:inc hl
    ld (hl),e:inc hl
    ld (hl),d:inc hl
    inc de,de
edup
    pop de

    ld a,c
    cp 16
    jr nz,nxt_c
    ld a,4*3
f2:
    ld (hl),$D5:inc hl
    dec a:jr nz,f2
nxt_c:

    call nbde
    inc b
    jp nz,f1
    ld b,$C0


    ld a,c
    add a,8
    ld c,a
    cp 24:jp nz,f1

    ld (hl),$31:inc hl
    ld (ous+2),hl
    inc hl,hl
    ld (hl),$C9:inc hl


....ниже кода

nbde    INC D:LD A,D:AND 7:RET NZ
        LD A,E:ADD A,#20:LD E,A:RET C
        LD A,D:SUB 8:LD D,A:RET
ous: ld (0),sp
ou


Прежде чем, начать рисование, нужно подготовить данные.

Каждое значение из таблицы синуса можно разбить на

X/8 - побайтное смещение для букв

X mod 8 - значение сдвига данных 0-7

При сдвиге байта вправо получится, что данные выйдут за пределы 8 бит, поэтому понадобится 16 бит.

Для простоты были подготовлены lookup table, где хранились нужные значения.

Например, по адресу $B001,$B101 хранится 1,0 по адресам  $B201,$B201: 0,128(сдвиг значени 1 вправо 1 раз)

Картина будет такой:

N:00011000.00000000 значение байта

0:00011000.00000000 сдвиг 0 адреса $B000-$B100

1:00001100.00000000 ..

2:00000110.00000000

3:00000011.00000000

4:00000011.00000000

5:00000001.10000000

6:00000000.11000000

6:00000000.01100000 сдвиг 7

init:
;pregenerate shifts
    ld hl,$B000
    ld b,l
ro1:
    push bc
    ld d,l
    ld e,0
ro2:
    ld a,b:or a:jr z,ro3
    srl d:rr e:djnz ro2
ro3:
    pop bc
    ld (hl),d:inc h
    ld (hl),e:dec h
    inc l:jp nz,ro1
    inc h,h
    inc b
    bit 3,b
    jp z,ro1

;синусы
    ld hl,st
    ld de,$AE00
i1:
    ld a,(hl)
    and 7
    add a,a;*2
    or $B0
    ld (de),a:inc d
    ld a,(hl):inc hl
    srl a
    srl a
    srl a
    ld (de),a:dec d
    inc e
    jp nz,i1

Заняли данные 4096 байт.

Для хранения текста использовался один трюк, я нашел идею в одной демо:

Для вывода понадобится 192 линии, достаточно буфера размером 256 байт,

копирование данных не понадобится.

Процедура рисования букв в странице выглядела просто:

;calc position
sip:    ld hl,$AE00 ; здесь хранятся старшие байты адреса таблиц сдвига
    inc l,l;,l
    ld (sip+1),hl

    exx
sva1:
    ld hl,$AD00 ; буффер текста для шрифта
    inc l
    ld (sva1+1),hl
    exx

    xor a
    ld (ds+1),a
pi:
    ld d,$C0 ; цикл 64
hu:
    ld b,(hl) ; адрес таблицы сдвига
    exx
    ld a,(hl)
    inc l
    exx
    ld c,a
    inc h
    ld a,(hl) ; смещение на 8 байт
ds: add a,0
    ld e,a
    dec h
    inc l
    ld a,(bc),(de),a
    inc b
    inc e
    ld a,(bc),(de),a
    inc d
    jp nz,hu

; 64 линии нарисованы, осталось прибавить 8

    ld a,(ds+1)
    add a,8
    ld (ds+1),a
    cp 16+8
    jp nz,pi

Осталась только печать букв, разобраться будет несложно.