ИФК: О своих успехах в освоении ассемблера решил написать Хороших Дмитрий из города Сосенский, Калужской области.
КОРР: Совсем недавно, после прочтения книги "ИНФОРКОМА" о программировании в машинных кодах (КИ1), я начал писать программы на Ассемблере (и что самое интересное -они даже начали работать). Я хочу предложить свою процедуру для заполнения экрана. Такой эффект я видел в игре "CJ in the USA" Я не стал взламывать программу, а решил написать свою процедуру, которая бы воспроизводила такой эффект. Идея алгоритма пришла мне в голову во время просматривания в книге Инфоркома "Элементарная графика" процедуры для закраски части экрана. Там используется конвейерная организация стека, которую я и применил в своей программе.
Процедура занимает всего 188 байт (без буфера). Экран обязательно должен располагаться с адреса 32768. Программе также требуется некоторая область памяти (100 байт в большинстве случаев будет предостаточно), которая определяется в строках 1070 и 1080. STK B F это физическая верхняя граница (конец) стека. В листинге под стек отдана область памяти с 41000 по 41100. Благодаря строкам 760-900 при "доезжании" конвейером до конца отданной ему области памяти, он автоматически копируется в начало, и таким образом использует отданную ему область памяти циклически. Программа может заполнять экран параллельно с любого количества мест. Это определяется заполнением конвейера: нужно занести в STK_BEG, которая является началом буфера, 41000, а в область памяти, начиная с 41000, координаты тех точек, с которых программа должна заполнять экран: сначала X, потом Y.
Например, для трех точек (10,6), (16,16) и (22,6) область памяти с 41000 по 41005 будет содержать значения 10,6,16,16,22,6. В переменной STKEND в таком случае должно быть 41006, т.е. она указывает на адрес на единицу больший, чем конец буфера. Единственным ограничением при использовании процедуры является то, что на экране не может быть знакоместа с атрибутом 0 (т.е. черный цвет на черном фоне). Я не думаю, что это серьезное ограничение, а процедура использует это для распознования тех мест, где она еще не закрасила экран.
Кстати, этот факт может использоваться для усложнения эффекта: например, если между строками 110 и 120 изменить цвет различных частей экрана на отличный от 0, то заполнение не коснется этих частей экрана, а если в каждом знакоместе объединить вывод цветовой и графической информации, то можно будет в один экран "впечатывать" фрагмент любого другого экрана, причем фрагмент произвольной формы. Достаточно только отметить этот участок атрибутом 0. Это может делать, например, процедура PRINT, вызов которой вставляется между строками 530 и 540. В таком случае строки 80-110 не нужны вообще, а строки 30-70 не нужны в том случае, когда пользова-
этюды
те ль сам заполнит нужный уча-
Процедура заполнения экрана: FILL SCREEN
ORG 40000 ENT
LD HL,#5800
LD DE,#5801
LD BC,#2FF
LD (HL),L LDIR
LD HL,#8000
LD DE,#4000
LD ВС, #1800 LDIR
LD HL,(STKJ3EG)
LD D,(HL)
INC HL
LD E,(HL)
INC HL
LD (STK_BEG)
PUSH DE
LD A,E
OR A
JR Z,CONT_1
DEC E
CALL VERIFY
POP DE
PUSH DE
LD A.E
CP 28
JR Z,CONT_2
INC E
CALL VERIFY
POP DE
PUSH DE
LD A.D
OR A
JR Z,CONT_3
DEC D
CALL VERIFY
POP DE
PUSH DE
LD A.D
CP 31
JR Z,CONT_4
INC D
CALL VERIFY
POP DE
CALL TRANS
10 20 30 40 50 60 70 80 90 100 110
120 BEGIN 130 140 150 160 170 180 190 200 210 220 230
240 CONTJ
250
260
270
280
290
300
310 CONT.2
320
330
340
350
360
370
380 CONT_3
390
400
410
420
430
440
450 CONT_4 460
; экран
; заполняется ; атрибутом 0
;копирование ; графической ; информации ; на экран ; снятие координат ; с вершины конвейера и занесение в DE ; X -> DE, Y -> DE
; сохраним DE ; если Y=0, то на ; CONTJ
; иначе проверка ; точки сверху ; восстановим DE ; снова сохраним ; если Y=28, то на ; CONT_2
; иначе проверка точки снизу
; аналогично ; слева
снимаем DE со стека вызов процедуры расчета ад-
аналогично справа
ЭТЮДЫ
реса в экранной области
470 |
LD |
E.L |
; преобразование |
480 |
LD |
A,H |
старшего байта |
490 |
AND |
#03 |
адреса для буферного |
500 |
OR |
#98 |
экрана |
510 |
LD |
D.A |
|
520 |
LD |
A,(DE) |
копирование атрибута |
530 |
LD |
(HL),A |
из буфера в экран |
540 |
LD |
DE,(STK BEG) |
; проверка, не кончились ли |
550 |
LD |
HL,(STK END) |
; значения на конвейере |
560 |
SBC |
HL.DE |
если да то конец |
570 |
RET |
Z |
|
580 |
LD |
B,#FF |
|
590 PAUSE |
DJNZ |
PAUSE |
пауза |
600 |
JR |
BEGIN |
все сначала |
610 VERIFY |
CALL |
TRANS |
; пересчет координат |
620 |
LD |
A,(HL) |
; проверка атрибута |
630 |
OR |
A |
на экране |
640 |
RET |
NZ |
; если не ноль - конец |
650 |
LD |
A,63 |
иначе атрибут 63 (белый |
660 |
LD |
(HL),A |
по белому) и |
670 |
LD |
HL,(STK END) |
занесение координат |
680 |
LD |
(HL),D |
на конвейер |
690 |
INC |
HL |
|
700 |
LD |
(HL),E |
|
710 |
INC |
HL |
|
720 |
LD |
(STK END),HL |
проверка - не достиг ли |
730 |
LD |
DE,(STK E F) |
конец конвейера |
740 |
SBC |
HL.DE |
физического конца |
750 |
RET |
NZ |
если нет, то конец |
760 |
LD |
HL,(STK END) |
иначе вычисляется |
770 |
LD |
DE,(STK BEG) |
; длина конвейера... |
780 |
SBC |
HL.DE |
|
790 |
LD |
B,H |
|
800 |
LD |
C,L |
|
810 |
PUSH |
HL |
сохраняется |
820 |
LD |
HL,(STK BEG) |
и конвейер копируется |
830 |
LD |
DE,(STK E F) |
в начало отведенной |
840 |
PUSH |
DE |
; ему области памяти |
850 |
LDIR |
|
|
860 |
POP |
DE |
высчитываются новые |
870 |
LD |
(STK BEG),DE |
начало и конец |
880 |
POP |
HL |
конвейера |
890 |
ADD |
HL.DE |
|
900 |
LD |
(STK END),HL |
|
910 |
RET |
|
|
920 TRANS |
LD |
A,E ; на входе в DE - координата |
930 |
AND |
#18 |
в знакоместах |
940 |
RRA |
|
в D - X, E - Y |
950 |
RRA |
|
на выходе в HL - адрес |
960 |
RRA |
|
; в файле атрибутов |
970 |
OR |
#58 |
|
980 |
LD |
H,A |
|
990 |
LD |
A.E |
|
1000 |
AND |
#07 |
|
1010 |
RRCA |
|
|
1020 |
RRCA |
|
|
1030 |
RRCA |
|
|
1040 |
ADD |
A,D |
|
1050 |
LD |
L,A |
|
1060 |
RET |
|
|
1070 STK_B_F 1080 STK_E_F 1090 STK.BEG 1100 ST К END
1110 ORG 41000
1120 DEFB 10,6
1130 DEFB 16,16
1140 DEFB 22,6
занесение координат на конвейер
Текст процедуры PRINT:
PRINT |
|
|
|
10 PRINT |
LD |
A,H |
пересчет адреса из файла |
20 |
AND |
#03 |
; атрибутов в дисплейный файл |
30 |
RLCA |
|
изменяется только старший байт |
40 |
RLCA |
|
|
50 |
RLCA |
|
|
60 |
OR |
#40 |
|
70 |
LD |
H,A |
; в HL - адрес на экране |
80 |
AND |
#18 |
|
90 |
OR |
#80 |
|
100 |
LD |
D,A |
в DE - адрес в буферном экране |
110 |
LD |
B,#08 |
|
120 REP 1 |
LD |
A,(DE) |
копирование восьми |
130 |
LD |
(HL),A |
; пиксельных линий |
140 |
INC |
D |
; знакоместа |
150 |
INC |
H |
|
160 |
DJNZ |
REP 1 |
|
170 |
RET |
|
|