Ликбез - Ассемблеp - взгляд издалека: работа с графикой.
Ассемблеp - взгляд издалека.
Продолжение.
Начало в || 20, 21, 24, 25, 28-30,
32, 33, 35, 36
{} Инфарх, 2000
Вот мы и снова встретились! После рас-
сказа о распределении памяти Speccy вы на-
верняка полны желания использовать полу-
ченную информацию по назначению, написав
какую-нибудь программу; в этом я вам пос-
тараюсь помочь.
Не секрет, что каждый программист желает
видеть, как работает его программа. Для
этого он должен организовать в своей прог-
рамме интерфейс общения с пользователем.
Начаать надо со средств вывода, а именно -
с экрана. Итак...
Общая организация экрана
Не исключено, что по Бейсику вы уже зна-
комы с делением экрана на строки, знако-
места и т.д. Но если вы всё-таки этого не
знаете, то прочитайте этот раздел внима-
тельно.
Минимальной единицей экрана является од-
на его точка - пиксел (от англ. "picture
element", pixel - элемент изображения).
Собранные в матрицу 8х8, точки образуют
знакоместо. В нём размещается стандартный
символ. Для знакоместа также определяется
атрибут - цвет пиксела установленного и
цвет пиксела, сброшенного в знакоместе.
Экран содержит 24 строки по 32 знакомес-
та в каждой. Если необходимо указать коор-
динаты определённого знакоместа, то отсчёт
ведётся от верхнего левого угла экрана.
Расположеное там знакоместо имеет коорди-
наты 0, 0. Знакоместо справа от него имеет
координаты 1, 0, а снизу - 0, 1. Знакомес-
то в нижнем правом углу имеет кординаты
31, 23.
Перейдём к графике. На более низком
уровне экран делится на столбцы (верти-
кальные) и линии (горизонтальные). Всего
экран содержит 192x256 пиксел. Пиксел сле-
ва вверху имеет координаты 0, 0, а справа
внизу - 255, 191. Младшие три бита коорди-
наты Х определяют, какой бит в байте адре-
са соответствует данному пикселу.
А теперь посмотрим, как всё это выводит-
ся на экран.
В Спектруме его экрану соответствует об-
ласть памяти, начинающаяся с адреса #4000.
В её начале определяется графика, а затем
- атрибуты. Каждый байт в области графики
определяет состояние восьми пикселов экра-
на. Пиксел будет изображён на экране, если
в байте будет установлен соответствующий
бит. Например, возьмём байт %10011101. Пе-
решлём его по адресу #4000 и посмотрим на
экран. Видите, в самой верхней линии у ле-
вого края экрана появились точки? Они име-
ют вот такой вид:
█ ░ ░ █ █ █ ░ █
░ - нет точки
█ - есть точка
Легко понять соответствие битов и точек,
сравнив пересланый в экран бит и получен-
ное изображение: каждый байт в экранной
области памяти соответствует 8-ми точкам и
равен ширине знакоместа.
Зная, что экран состоит из
32 х 24 = 768 знакомест,
причём каждое знакоместо имеет по вертика-
ли 8 линий (8 байт), нетрудно получить
размер области графики в байтах:
32 х 24 х 8 = 6144 (#1800) байт
Теперь - об атрибутах. Их область памяти
расположена сразу за графической областью,
начиная с адреса #5800. Т.к. атрибут зада-
ётся для целого знакоместа (а знакомест у
нас - 768) и каждый атрибут занимает один
байт, то нетрудно вывестии и размер облас-
ти атрибутов - 768 байт.
Вот как этот байт определяет состояние
экрана:
- три младших бита (D2, D1, D0) задают
цвет чернил (INK, установленныe пикселы);
- биты D5, D4, D3 - цвет бумаги (PAPER,
пикселы сброшенные);
- бит D6 определяет яркость (BRIGHT);
если он установлен, то информация на экра-
не для данного знакоместа отображается с
повышеной яркостью.
Остался бит D7 - бит мерцания (FLASH).
Если он включен, то через каждые 16/50 до-
лей секунды ULA меняет местами цвет бумаги
и чернил для данного знакоместа.
Рассмотим байт атрибута в общей форме:
Paper
┌────┐
┌──┬──┬──┬──┬──┬──┬──┬──┐
│D7│D6│D5│D4│D3│D2│D1│D0│
└──┴──┴──┴──┴──┴──┴──┴──┘
│ │ └────┘
│ └Bright Ink
└Flash
Цвета для экрана Спектрума имеют следую-
щее соответствие кодов:
0 чёрный
1 ███ синий
2 ███ красный
3 ███ малиновый
4 ███ зелёный
5 ███ циан
6 ███ жёлтый
7 ███ белый
Организация экранной памяти
Ознакомившись с экранной памятью Спек-
трума, не подумайте, что она организована
линейно! Её структура более сложная, в чём
мы сейчас и убедимся. Наберите и запустите
такую программу:
LD HL,#4000 ; Очищаем экран
LD DE,#4001
LD BC,#1800
LD (HL),L
LDIR
LD BC,#2FF ; И устанавливаем
; его атрибут
LD (HL),7 ; ink=7, paper=0
LDIR
LD HL,#4000 ; Начало экранной
; памяти
LD DE,#1800 ; Размер
; графической
; области
SCR
LD (HL),#FF ; Пересылаем
; в экран
INC HL ; Следующий байт
; экрана
; Задержка 1/10 секунды для наглядности
LD B,5
PAUSE
HALT
DJNZ PAUSE
; Повторяем для всей области графики
DEC DE
LD A,D
OR E
JR NZ,SCR
RET
Назначение этой, весьма простой про-
граммы - последовательное заполнение об-
ласти памяти графики экрана значением #FF,
что соответствует одной закрашеной линии
знакоместа. Кстати, если вы испoльзуете
ассембер XAS, запускайте эту программу,
используя комбинацию клавиш CS+R, - и вы
сможете после завершения работы программы
лицезреть получившееся изображение столь-
ко, сколько угодно. Лишь после нажатия
"any key" (не путать с RESET) вы вернётесь
в редактор.
Теперь рассмотрим специфику работы све-
женабранной программы более подробно.
Итак, первые 32 байта экранной памяти
соответствуют первой линии первой строки
знакомест. Впрочем, вы это видели. Навер-
ное, вы подумали, что далее следует вторая
линия первой строки? А вот и нет! Далее
следует первая линия второй строки! И так
последовательно заполняются все 8 строк -
от первой до восьмой.
Можно предположить, что следующий байт
будет соответствовать первой линии девятой
строки... Но это опять-таки неверно. Оче-
редь заполнения возвращается к первой
строке, на этот раз - ко второй линии. И
вот так, по линии из каждой строки знако-
мест, заполняются все восемь строк.
Как вы уже могли заметить, экран разде-
ляется на трети и переход на следующую
треть происходит только после заполнения
предыдущей. Конечно, такая организация эк-
рана создаёт определённые сложности для
программиста, но при некоторой ловкости
рук это легко решается. О технических под-
робностях поговорим потом, а сейчас зай-
мёмся областью атрибутов.
Честно говоря, особо заниматься ею и не
придётся. В отличие от графики, атрибуты
организованы совершенно линейно. Сначала
последовательно (слева направо) заполняет-
ся нулевая строка, далее очередь переходит
к первой, и так до конца экрана. Дабы про-
иллюстрировать всё вышесказанное, обратим-
ся опять-таки к программе.
В предыдущем примере удалите последнюю
команду (RET) и с этой позиции введите та-
кие строки:
LD DE,#300 ; Размер области
; атрибутов
ATTR
LD (HL),2
INC HL
LD B,5
PAUSE1
HALT
DJNZ PAUSE1
DEC DE
LD A,D
OR E
JR NZ,ATTR
RET
Вот вам наглядная демонстрация всего вы-
шесказанного! Как видите, работа с атрибу-
тами весьма проста.
А теперь отвлечёмся на некоторое время
от освоения экрана и глянем повнимательнее
на ту программу, которую вы только что
набрали. Естественно, она не идеальна.
Ведь это только пример, в котором нагляд-
ность - важнее всего. А вот давайте попро-
буем записать его так, чтобы он был как
можно более компактным. Тем более, что все
команды ассемблера вам уже известны.
Итак...
LD HL,#4000
PUSH HL
LD DE,#4001
LD BC,#1800
PUSH BC
LD (HL),L
LDIR
LD BC,#2FF
LD (HL),7
LDIR
POP BC
POP HL
LD E,#FF
CALL FILL
LD E,2
LD BC,#300
FILL
LD (HL),E
INC HL
LD D,5
WAIT
HALT
DEC D
JR NZ,WAIT
DEC BC
LD A,B
OR C
JR NZ,FILL
RET
Проанализировав на досуге эту програмку,
вы наверняка поймёте её принцип работы.
А мы вернёмся к экранным операциям.
Узнав методику распределения экранной
памяти, следует научиться и тому, как на-
ходить в экране адрес необходимого байта
(пока только байта, до пикселей мы добе-
рёмся позже).
Вычислить адрес первого байта первого
знакоместа в строке, номер которой переда-
ётся через регистр А, вам позволит такая
программа:
LD H,A ; В "А" находится
; номер строки
RRCA
RRCA
RRCA
AND #E0
LD L,A
LD A,H
AND #18
OR #40
LD H,A
; На выходе в HL адрес первого байта
; заданной строки
Вот и вся сложность. Не забудьте только,
что если вы хотите использовать процедуру
как подпрограмму, то в конце необходимо
добавить команду RET. Если вы проследите
за выполнением процедуры пошагово, причём,
обращая внимание на содержимое аккумулято-
ра в двоичной форме, то без труда поймёте
принцип работы.
А теперь попробуем несколько изменить
пример, чтобы получить возможность расчёта
адреса с учётом ещё и столбца. Если в пре-
дыдущем примере мы в качестве аргумента
использовали номер строки в регистре А, то
здесь надо будет использовать ещё и номер
столбца в регистре L. Смотрите:
LD H,A
RRCA
RRCA
RRCA
AND #E0
ADD A,L ; Добавленная строка
LD L,A
LD A,H
AND #18
OR #40
LD H,A
Как видите, путём добавления всего одной
команды пример был доработан до более
сложного. Попробуйте теперь сделать так,
чтобы расчитывался адрес любой линии экра-
на (0..191). Наверняка это окажется полез-
ным упражнением.
Ну, поехали дальше...
Очень редко бывает необходимо что-либо
делать в пределах одной линии пикселей.
Обычно изображение занимает по вертикали
гораздо больше места. И для того, чтобы
перейти на следующую линию, вовсе не обя-
зательно заново высчитывать её адрес. На-
пример, если вам нужна следующая линия в
пределах знакоместа (при печати символа),
достаточно провести инкремент старшего
байта адреса.
На тот случай, если переход должен быть
осуществлён без привязки к знакоместу, а
просто на следующую строку в пределах эк-
рана, предлагаю вашему вниманию небольшую
подпрограмму:
DOWN_HL
INC H
LD A,H
AND 7
RET NZ
LD A,L
ADD A,#20
LD L,A
RET C
LD A,H
SUB 8
LD H,A
RET
На входе сия процедура получает адрес
байта в экране, а на выходе выдаёт адрес
байта, расположенного под ним. Заметьте,
это вовсе не должен быть первый байт ли-
нии. Если вы предпочитаете использовать не
регистр HL, а нечто иное, то просто заме-
ните соответствующие регистры в процедуре.
А заодно, раз уж зашёл разговор на эту те-
му, посмотрите и на процедуру, выполняющую
действие прямо противоположное - рассчиты-
вает адрес строки предыдущей:
UP_HL
DEC H
LD A,H
AND 7
CP 7
RET NZ
LD A,L
SUB #20
LD L,A
RET C
LD A,H
ADD A,8
LD H,A
RET
Иногда бывает нужно пересчитать адрес в
экране в адрес, соответствующий данному
знакоместу в области атрибутов. Сделать
это можно так:
SCR_ATR
LD A,H
RRCA
RRCA
RRCA
AND 3
OR #58
LD H,A
RET
Ну, на этот раз пока хватит.
До следующего урока попробуйте позани-
маться написанием программ для рисования
графических примитивов - для практики это
весьма полезно.
Удачи!
Продлжение следует...
──══════════──
Другие статьи номера:
|
|
|
|
|
|
Ликбез - Ассемблеp - взгляд издалека: работа с графикой.
|
|
|
|
|