ИСПОЛЬЗОВАНИЕ СПРАЙТОВ В БЕЙСИК-ПРОГРАММАХ НА "КОРВЕТЕ"
Графическое изображение строится различными способами. Рисовать картинки на экране можно с помощью графических операторов Бейсика или используя библиотеки Си, Паскаля, EXPRESS-PASCAL. Но эти методы не всегда устраивают.
Бейсик имеет малое быстродействие, а программирование на Си и Паскале затруднительно для начинающих программистов. Кроме того, эти компиляторы включают библиотеки, что заметно увеличивает объем программы.
Авторы данной статьи видят выход в методе построения изображений с помощью ассемблерных вставок в Бейсик-программы. Такой способ наиболее удобен, так как сочетает простоту создания программ, присущую Бейсику, с быстродействием ассемблера. В частности, таким образом с помощью операторов Бейсика можно создавать массивы изображений, не требующих высокого быстродействия и состоящих из простых фигур, например рамки поля. С помощью же ассемблерных вставок можно строить спрайты, причем любых размеров (разумеется, в пределах графического экрана).
В общем случае алгоритм рисования выглядит следующим образом. Допустим, вам понадобилось нарисовать картинку на бумаге. Что вы для этого сделаете? Вы возьмете: (1) - лист чистой бумаги; (2) -набор имеющихся у вас красок, т.е. выберете палитру; (3) - выберете нужный цвет и (4) - начнете рисовать, нанося мазки краски на лист бумаги. Мы специально выделили последовательность действий, потому что "Корвет" для того, чтобы что-то нарисовать, поступает таким же образом.
Для вывода графических изображений на экран используется специально отведенная область памяти, называемая графическим запоминающим устройством (ГЗУ), или видеопамятью. ГЗУ как бы проецирует свое содержимое на экран дисплея; одной ячейке видеопамяти соответствует один элемент экрана.
Существует несколько способов вывода информации на экран. В одном из них за каждую точку экрана отвечает одна ячейка ГЗУ, в которой хранится информация о цвете точки, интенсивности ее свечения, а также о том, зажжена она или нет. В другом способе цвет и интенсивность свечения точки определяются заранее перед процедурой рисования, а каждая ячейка ГЗУ сообщает о включении целой группы точек. Образно говоря, если в первом случае рисунок состоял бы из точек, то во втором - из штрихов. У каждого способа есть свои достоинства и недостатки; не будем здесь о них говорить, отметим только, что "Корвет" рисует, используя второй способ.
Наш компьютер применяет байтовую графику, т.е. при одном обращении к ячейке ГЗУ он выводит сразу 8 точек одного цвета. Давайте подсчитаем, какой объем оперативной памяти понадобится для этого. Как известно, "Корвет" имеет графику высокого разрешения - 512*256 точек. Если использовать первый метод рисования, то понадобится 512*256=131072 байт памяти, или 128 Кбайт. В нашем случае при рисовании одновременно 8 точек понадобится всего 131072/8=16384 байт, или 16 Кбайт. Именно такой объем имеет включаемый в адресное пространство компьютера сегмент ГЗУ.
Но самое интересное на этом не заканчивается. Наиболее распространенный вариант компьютера имеет ГЗУ объемом 48 Кбайт. Оно разделено на три плоскости объемом по 16 Кбайт. При начальной инициализации этим плоскостям присваиваются физические цвета, но в процессе работы программы вы можете их перепрограммировать. Программист может использовать для вывода графики как одну плоскость, так и все сразу. В первом случае режим работы с ГЗУ называется послойным, а во втором - цветовым. При работе в послойном режиме процессор обращается только к текущей плоскости, заданной маской регистра цвета, т.е. не к 48, а только к 16 Кбайт. При использовании цветового режима происходит наложение плоскостей, и суммарный объем ГЗУ составит также 16 Кбайт, которые включаются как сегмент ОЗУ в адресное пространство компьютера в конфигурациях ROMB2, BASG, DOSG1, DOSG2.
Но и это еще не все. Авторская концепция подразумевает существование четырех независимых границ ГЗУ, которые практически мгновенно могут переключаться. Используя этот принцип, можно очень легко реализовать мультипликацию. Чтобы не обольщать читателей, надо сразу сказать, что в компьютерах производства г.г. Баку, Минск, С.-Петербург, Каменск-Уральский реализована только одна страница, а значит, описанный выше подход неприемлем.
ГЗУ может быть включено в карту памяти либо с адреса 0С000Н по 0FFFFH, либо с 4000Н по 8000Н. Программист сам должен выбрать нужную конфигурацию для решения своих задач. Например, для использования графических функций на ПК8010 (конфигурация BASIC) рекомендуется использовать BASG. При использовании ОС СР/М или МикроДОС лучше применять DOSG1, DOSG2. Наиболее привлекательной является конфигурация ROMB2, которая, кроме ОЗУ, содержит набор драйверов, АЦЗУ, ГЗУ, т.е. оптимальный набор компонентов для работы с дисплеем. Эта конфигурация позволяет достаточно просто совмещать текстовый и графический экраны.
Из сказанного следует, что перед тем как начать процедуру рисования, необходимо переключиться в конфигурацию, содержащую ГЗУ. Сделать это можно, воспользовавшись "услугами" системного регистра. Но прежде нужно обратить внимание на следующий момент: при переключении конфигурации памяти следует специальной командой процессора запретить прерывания, иначе можно увидеть очень интересное изображение на экране, неизбежно заканчивающееся появлением девяток, и, увы, совсем не то, которое задумывалось.
Перейдем к определению цвета рисования. Цвета определяет другая специальная ячейка памяти - регистр цвета. Он находится на той же странице, что и системный регистр, но его относительный адрес равен 0BFH. Например, для конфигурации BASG адрес регистра цвета будет составлять 0BFBFH, а для ROMB2 - 3ABFH. С помощью регистра цвета можно также задавать режим рисования - цветовой или послойный. Для создания процедуры рисования спрайтов нас будет интересовать цветовой режим записи в ГЗУ.
Рассмотрим подробнее формат регистра цвета. В нем каждый бит несет свою смысловую нагрузку.
|
||||||||||
D1-D3 | - | определяют плоскости для чтения в ГЗУ; | ||||||||
D4-D6 | - | определяют плоскости для записи в ГЗУ; | ||||||||
D7 | - | режим работы. |
При работе в цветовом режиме бит D7 равен 1, а биты D3 - D1 указывают, какие плоскости будут участвовать в процессе рисования. Содержимое битов D6 - D4 и D0 в данном случае значения не имеет. Комбинация битов D3 - D1 будет определять цвет записываемого байта. Здесь нужно учесть, что таким образом будет присвоен логический (т.е. условный) цвет, а физический определяется с учетом программирования просмотровой таблицы. Допустим, вы хотите нарисовать байт логического цвета 5 (если таблицу цветов перед рисованием не перепрограммировали, то логический цвет будет соответствовать физическому, т.е. фиолетовому). В этом случае в регистр цвета вам нужно записать двоичное число 1000101х, где содержимое бита, обозначенного как "х", не имеет значения (в шестнадцатеричном виде - 8АН или 8ВН, в зависимости от значения бита D0).
Теперь вы знаете, как выбрать "лист бумаги" и подготовить "карандаш" нужного цвета; остается научиться собственно рисовать. Как это сделать? После вышеуказанных действий вы должны заносить в ГЗУ байты, соответствующие выбранному вами рисунку и месту на экране дисплея. Покажем, как это делается. Возьмем, к примеру, конфигурацию BASG, содержащую ГЗУ, которое начинается с адреса 0С000Н и занимает область до адреса 0FFFFH. Байт 0FFH, записанный по адресу 0С000Н, вызовет появление на экране линии, состоящей из восьми точек и расположенной в левом верхнем углу, т.е. соответствует оператору Бейсика LINE (0,0)-(8,0). Так как по горизонтали "Корвет" рисует 512 точек, то это составит 512/8=64 байт, т.е. одна строка состоит из 64 байт (40Н). Значит, адрес 0C03FH будет соответствовать отрезку, находящемуся в правом верхнем углу, т.е. LINE (504,0)-(512,0).
Читатель теперь, вероятно, вычислит сам, в каком месте экрана будет находиться отрезок, соответствующий адресу 0FFFFH.
Теперь можно перейти к созданию процедуры рисования спрайтов. Предложенная авторами методика позволяет создавать спрайты любых размеров в пределах графического экрана.
Представленная процедура рисования состоит из двух частей: составления самой программы рисования и формирования блока данных. Причем сама программа рисования будет фактически одинаковой для любых спрайтов. В ней будут меняться только некоторые параметры (цвет, размеры по горизонтали, по вертикали, месторасположение). Значительно изменяться будет только блок данных. Ниже мы покажем, как его составлять. Пусть нам потребовалось нарисовать яблоко. Прежде чем рисовать его на экране, сделаем макет на бумаге в клетку. Число клеток по горизонтали должно быть кратно 8, т.е. 8, 16, 24 и т.д. Если это не получается, необходимо сделать дополнение до 8 по горизонтали. Например, если рисунок яблока занял по горизонтали 14 клеток, для создания спрайта надо дополнить его до 16, т.е. пририсовать к левому (или правому) краю 2 клетки. Это делается для создания байтов блока данных (8 последовательно расположенных клеток составят один байт).
Клеткам, занимаемым рисунком, присвоим значение "1", а свободным - значение "0", таким образом мы получим массив двоичных чисел, которые легко можно преобразовать в набор байтов. В нашем случае это преобразование будет выглядеть следующим образом.
Двоичное выражение | Шестнадцатеричное выражение |
---|---|
00000100 00000000 | 04 00 |
00000010 00000000 | 02 00 |
00111010 11110000 | ЗА F0 |
01111111 11111000 | 7F F8 |
11111111 11111100 | FF FC |
11111111 11111100 | FF FC |
11111111 11111100 | FF FC |
11111111 11111100 | FF FC |
11111111 11111000 | FF F8 |
01111111 11111000 | 7F F8 |
01111111 11110000 | 7F F0 |
00111111 11100000 | 3F Е0 |
00011001 11000000 | 19 С0 |
Мы получили блок данных для рисунка. Нужно отметить, что при создании спрайта лучше пользоваться стандартными шаблонами, причем размер по вертикали (количество строчек) может быть любым. Теперь, имея блок данных, можно написать полную программу рисования яблока. Тут для удобства работы желательно использовать компилятор ассемблера. Итак, для спрайта "яблоко" имеем:
LEN : EQU 2H ; LEN - значение длины спрайта по горизонтали,
HIGH: EQU 0DH ; равно количеству байтов
PLACE: EQU 0DD20H ; HIGH - количество строк в спрайте,
DI ; т.е. размер по вертикали
MVI А,6СН ; PLACE - адрес места спрайта на экране
STA 0FA7FH ; Переключение в конфигурацию DOSG2
MVI A,8FH ; Выбор цвета 8FH - белый цвет
STA 0BFBFH
LXI Н,PLACE
LXI D,DATA ; Основная процедура рисования
MVI С,HIGH ; В регистре С - счетчик числа строк
PUSH Н ; Сохраняем начальную координату в стеке
STRING: MVI В,LEN ; В регистре В - счетчик числа байтов
LOOP: LDAX D ; В строке
MOV М,А ; Далее идет стандартная процедура
INX Н ; копирования
DCRB
NZ LOOP ; Строка закончилась ?
POP Н ; Если да, то переход на следующую. Для
PUSH D ; этого извлекается из стека адрес начала
LXI D,0040Н ; строки и прибавляется 64 (40Н),
DAD D ; потом все восстанавливается
PUSH Н
POP D
DCRC
JNZ STRING ; Строчки закончились ?
HLT ; Если да, то останов
DATA: DB 04, 00, 02, 00, ЗАН, 0F0H, 7FH, 0F8H, 0FFH, 0FCH, 0FFH, 0FCH
DB 0FFH, 0FCH, 0FFH, 0FCH, 0FFH, 0F0H, 7FH, 0F8H, 7FH, 0F0H, 3FH
DB 0E0H, 19Н, 0C0H
END
Данная программа занимает 74 байт и будет выполнена за 1 мс (одна тысячная доля секунды). Авторы создавали спрайты размером 128400, при этом изображение появлялось фактически мгновенно. Кстати, можно модифицировать программу, уменьшив ее размер и время выполнения. Предоставим читателям самим поэкспериментировать в этом направлении.
Как вы уже заметили, данная программа легко настраивается на любые параметры спрайта. Изменением константы LEN можно изменять размер по горизонтали, a HIGH - по вертикали. Изменяя начальный адрес PLACE, можно перемещать спрайт. Можно также использовать другой цвет, меняя константу записи в регистре цвета.
А теперь проследим, как делается ассемблерная вставка в Бейсике. Для вызова подпрограмм на машинном языке служит оператор USR. Он имеет формат X=USR[n](адрес), где X - фиктивная переменная, а n - номер подпрограммы, определенный оператором DEFUSR[n]. Чтобы запустить программу на машинном языке, ее нужно разместить в памяти. Далее все примеры будут приводиться для интерпретатора Бейсик версии 1.0, работающей под управлением ОС СР/М. Эта программа работает и на МикроДОС, и на РМУ, только в этом случае используемые конфигурации и значения системного регистра должны быть другими.
Итак, машинные коды приведенной выше программы после создания командного файла будут иметь следующий вид (без блока данных):
0100 F3 ЗЕ 6С 32 7F FA ЗЕ 8F 32 BF BF 0Е 0Е 21 20 DD 0110 11 33 01 Е5 06 02 1А 77 23 13 05 С2 17 01 Е1 D5 0120 11 40 00 19 D1 Е5 0D С2 15 01 ЗЕ 1С 32 BF BF FB 0130 С9
Получить листинг можно, воспользовавшись программами DDT, PKTOOL или POWER. Добавим блок данных:
0130 С9 04 00 02 00 ЗА F0 7F F8 FF FC FF FC FF FC FF FC 0140 FF F0 7F F8 7F F0 3F Е0 19 С0
Это и есть наша подпрограмма рисования спрайта. Напишем теперь программу на Бейсике, использующую эту подпрограмму.
10 REM Размещение подпрограммы в памяти
15 CLS:CLEAR:FOR I=0 TO 74:READ C$:POKE &HBD00 + I,VAL("&H + C$):NEXT I
20 REM Определение и вызов подпрограммы
25 DEFUSR=&HBD00:X=USR(0)
30 DATA F3,3E,6C,32,7F,FA,3E,8F,32,BF,BF,0E,0E,21,20,DD
35 DATA 11,33,BD,E5,06,02,1A,77,23,13,05,C2,17,BD,E1,D5
40 DATA 11,40,00,19,D1,E5,0D,C2,15,BD,3E,1C,32,7F,BF,FB
45 DATA C9
50 REM Блок данных
55 DATA 04,00,02,00,ЗА,F0,7F,F8,FF,FC,FF,FC,FF,FC
60 DATA FF,F0,7F,F8,7F,F0,3F,E0,19,C0
Авторы намеренно выделили некоторые ячейки памяти в размещаемой подпрограмме. Изменяя содержимое этих ячеек, можно добиться нужных вам результатов. И еще, как вы заметили, мы разместили подпрограмму, начиная с адреса &HBD00, и поэтому в программе поменялись адреса переходов (если в дампе памяти значение перехода равно 0115, то в последнем случае будет BD15 и т.д.). Пользователь может разместить программу в любом месте ОЗУ, кроме области, занимаемой интерпретатором и ОС. Но авторы советуют размещать подпрограммы в самой верхней доступной пользователю части ОЗУ.
Рассмотрим ячейки памяти, которые можно изменять в вышеприведенной программе:
- &HBD07 - цвет ячейки;
- &HBD0C - количество строчек, вертикальный размер;
- &HBD0E, &HBD0F - месторасположение спрайта на экране;
- &HBD15 - количество байт в строчке, горизонтальный размер.
В качестве демонстрации покажем, как организовать перемещение спрайта по экрану. Сделать это можно, изменяя содержимое ячеек &HBDOE и &HBDOF. Простейшее горизонтальное передвижение спрайта реализуется так: надо изменить строку 25 приведенной Бейсик-программы и ввести еще одну строку.
25 DEFUSR=&HBD00:L=&HDD
26 PCLS:I=I+1:POKE &HBD0E,&H20+I: X=USR(O): IF PEEK(&HBDOE)=&HFF THEN POKE &HBD0E,0: POKE&HBD0F,L+1
27 GOTO 26
Опыт авторов в создании и использовании спрайтов показывает, что наиболее трудоемка операция составления блока данных. Для избавления от мучений сотрудниками МП "МикС" создан пакет редактора спрайтов EOS, который возложил на компьютер всю неблагодарную работу по созданию программы рисования и блока данных спрайта. Редактор EOS автоматически настраивается на текущую операционную систему и может работать, а значит, создавать программу рисования как на ОС типа МикроДОС и СР/М, так и на РМУ. При этом работа пользователя с редактором предельно проста, освоение занимает 15 минут. Применение редактора процессе обучения показало устойчивый интерес учащихся к предмету.