Из журнала Adventurer #7, Рыбинск, 1997
Веселов Евгений (VEKA/CPU)
Быстрые процедуры линии.
Представляю вам две программы рисо-
вания линии, работающие быстрее, чем рас-
положенная в ПЗУ.
Первая из них - для установки точки,
вызывает внешнюю подпрограмму, что позво-
ляет использовать ее для вывода любых об-
ъектов.
Координаты концов линии задаются в
регистрах HL и DE (E и L - x, D и H - y).
LINE LD A,H ;расчет смещений
SUB D
JR NC,LINE1
EX DE,HL ;линия рисуется снизу вверх
NEG ;смена знака смещения
LINE1 LD H,A ;H=dy=|y2-y1|
LD A,L
SUB E
LD BC,#141C ;INC D [#14], INC E [#1C]
JR NC,LINE2
INC C ;если x1dy
LD H,A
LD A,B ;замена INC D <-> INC/DEC E
LD B,C
LD C,A
LINE3 LD A,B ;модификация кода
LD (LINE5),A
LD A,C
LD (LINE6),A
LD B,H ;кол-во точек в линии
LD A,H
INC L
INC B
LINE4 CALL PLOT ;установка точки
LINE5 NOP
;изменение координаты с большим смещением
;направление зависит от знака смещения
SUB L
JR NC,LINE7
LINE6 NOP
;изменение координаты с меньшим смещением
ADD A,H
LINE7 DJNZ LINE4
RET
В PLOT должны сохраняться следующие
регистры: HL,DE,B,A. Координаты задаются
в регистре DE (E=x, D=y).
Следующая программа аналогична пре-
дыдущей, но работает непосредственно с
адресом в экранном файле. Также вместо
самомодифицируещегося кода используются
отдельные части программы для каждого из
четырех направлений. За счет этого значи-
тельно возрастает скорость и еще больше
длина ;-).
А откуда берутся четыре направления?
Посмотрите строчку после первого JR.
Видите EX DE,HL? Теперь посмотрите на ри-
сунок.
Если D(y1)>H(y2),то линия должна рисовать-
ся сверху вниз (линии 5..8 на рисунке), но
выполняется EX DE,HL и все линии рисуются
снизу вверх (как линии 1..4).
Все это относится и к первой проце-
дуре линии. Если необходимо, чтобы линия
всегда шла в заданном направлении, то вам
придется переделать начальный блок прог-
раммы (расчет смещений) или напишите в
редакцию журнала, и будет опубликован из-
мененный вариант.
Еще один важный момент: во второй
процедуре экранный адрес расчитывается
один раз перед выводом линии (см. в четы-
рех местах CALL GET_ADR). Координаты за-
даются в регистре DE,а результаты расчета
заносятся в регистр HL(адрес) и C(маска),
при этом можно использовать все регистры.
Самое главное, что начало координат при
этом должно находиться внизу экрана (об-
ратите внимание на вторую и третью строч-
ки в процедуре GET_ADR).
LINE LD A,H
SUB D
JR NC,LINE1
EX DE,HL
NEG
LINE1 LD H,A
LD A,L
SUB E
JR NC,LINER
NEG
CP H
LD L,A
JR C,LINELU
PUSH HL
CALL GET_ADR
POP DE
LD B,E
LD A,E
INC D
INC B
EX AF,AF'
LINELD1 LD A,(HL)
OR C
LD (HL),A
RLC C
JP NC,LINELD2
DEC L
LINELD2 EX AF,AF'
SUB D
JR NC,LINELD4
ADD A,E
EX AF,AF'
LD A,H
DEC H
AND 7
JP NZ,LINELD3
LD A,L
SUB #20
LD L,A
JR C,LINELD3
LD A,H
ADD A,8
LD H,A
LINELD3 DJNZ LINELD1
RET
LINELD4 EX AF,AF'
DJNZ LINELD1
RET
LINELU PUSH HL
CALL GET_ADR
POP DE
LD B,D
LD A,D
INC E
INC B
EX AF,AF'
LINELU1 LD A,(HL)
OR C
LD (HL),A
LD A,H
DEC H
AND 7
JP NZ,LINELU2
LD A,L
SUB #20
LD L,A
JR C,LINELU2
LD A,H
ADD A,8
LD H,A
LINELU2 EX AF,AF'
SUB E
JR NC,LINELU3
ADD A,D
RLC C
JP NC,LINELU3
DEC L
LINELU3 EX AF,AF'
DJNZ LINELU1
RET
LINER CP H
LD L,A
JR C,LINERU
PUSH HL
CALL GET_ADR
POP DE
LD B,E
LD A,E
INC D
INC B
EX AF,AF'
LINERD1 LD A,(HL)
OR C
LD (HL),A
RRC C
JP NC,LINERD2
INC L
LINERD2 EX AF,AF'
SUB D
JR NC,LINERD4
ADD A,E
EX AF,AF'
LD A,H
DEC H
AND 7
JP NZ,LINERD3
LD A,L
SUB #20
LD L,A
JR C,LINERD3
LD A,H
ADD A,8
LD H,A
LINERD3 DJNZ LINERD1
RET
LINERD4 EX AF,AF'
DJNZ LINERD1
RET
LINERU PUSH HL
CALL GET_ADR
POP DE
LD B,D
LD A,D
INC E
INC B
EX AF,AF'
LINERU1 LD A,(HL)
OR C
LD (HL),A
LD A,H
DEC H
AND 7
JP NZ,LINERU2
LD A,L
SUB #20
LD L,A
JR C,LINERU2
LD A,H
ADD A,8
LD H,A
LINERU2 EX AF,AF'
SUB E
JR NC,LINERU3
ADD A,D
RRC C
JP NC,LINERU3
INC L
LINERU3 EX AF,AF'
DJNZ LINERU1
RET
Далее приведены подпрограммы расчета
адреса в экране и установки точки, ис-
пользуемые при рисовании линий (установка
точки нужна только для первой процедуры).
PLOT PUSH HL ;установка точки
PUSH DE
EX AF,AF'
CALL GET_ADR
OR (HL)
LD (HL),A
EX AF,AF'
POP DE
POP HL
RET
GET_ADR LD A,#BF ;расчет адреса в экране
SUB D
LD D,A
SRL A
SCF
RRA
SRL A
XOR D
AND #F8
XOR D
LD H,A
LD A,E
RLCA
RLCA
RLCA
XOR D
AND #C7
XOR D
RLCA
RLCA
LD L,A
LD A,E
AND 7
INC A
LD C,B ;сохранение B
LD B,A
LD A,1
GETADR1 RRCA
DJNZ GETADR1
LD B,C ;восстановление B
LD C,A ;маска в c
RET
Эти подпрограммы приведены только
для примера. На практике лучше вставить
вычисление адреса и установку точки не-
посредственно в программу линии и ис-
пользовать для расчета таблицы (см.
ZX-Format N7 , "Кодинг для начинающих" ).
В приложении вы найдете исходники
этих процедур (LINE1 и LINE2).
-Приложение: LINE 1.C--------------------
ORG #8000
LD HL,0
LD DE,#BFFF
LINE LD A,H ;расчет смещений
SUB D
JR NC,LINE1
EX DE,HL ;линия рисуется снизу вверх
NEG ;смена знака смещения
LINE1 LD H,A ;H=dy=|y2-y1|
LD A,L
SUB E
LD BC,#141C;INC D [#14], INC E [#1C]
JR NC,LINE2
INC C ;если x1dy
LD H,A
LD A,B ;замена INC D <-> INC/DEC E
LD B,C
LD C,A
LINE3 LD A,B ;модификация кода
LD (LINE5),A
LD A,C
LD (LINE6),A
LD B,H ;кол-во точек в линии
LD A,H
INC L
INC B
LINE4 CALL PLOT ;установка точки
LINE5 NOP
;изменение координаты с большим смешением
;направление зависит от знака смешения
SUB L
JR NC,LINE7
LINE6 NOP
;изменение координаты с меньшим смешением
ADD A,H
LINE7 DJNZ LINE4
RET
PLOT PUSH HL ;установка точки
PUSH DE
EX AF,AF'
LD A,#BF ;расчет адреса в экране
SUB D
LD D,A
SRL A
SCF
RRA
SRL A
XOR D
AND #F8
XOR D
LD H,A
LD A,E
RLCA
RLCA
RLCA
XOR D
AND #C7
XOR D
RLCA
RLCA
LD L,A
LD A,E
AND 7
INC A
LD C,B ;сохранение B
LD B,A
LD A,1
GETADR1 RRCA
DJNZ GETADR1
LD B,C ;восстановление B
OR (HL)
LD (HL),A
EX AF,AF'
POP DE
POP HL
RET
-Приложение: LINE 2.C--------------------
ORG #8000
LD HL,0
LD DE,#BFFF
LINE LD A,H
SUB D
JR NC,LINE1
EX DE,HL
NEG
LINE1 LD H,A
LD A,L
SUB E
JR NC,LINER
NEG
CP H
LD L,A
JR C,LINELU
PUSH HL
CALL GET_ADR
POP DE
LD B,E
LD A,E
INC D
INC B
EX AF,AF'
LINELD1 LD A,(HL)
OR C
LD (HL),A
RLC C
JP NC,LINELD2
DEC L
LINELD2 EX AF,AF'
SUB D
JR NC,LINELD4
ADD A,E
EX AF,AF'
LD A,H
DEC H
AND 7
JP NZ,LINELD3
LD A,L
SUB #20
LD L,A
JR C,LINELD3
LD A,H
ADD A,8
LD H,A
LINELD3 DJNZ LINELD1
RET
LINELD4 EX AF,AF'
DJNZ LINELD1
RET
LINELU PUSH HL
CALL GET_ADR
POP DE
LD B,D
LD A,D
INC E
INC B
EX AF,AF'
LINELU1 LD A,(HL)
OR C
LD (HL),A
LD A,H
DEC H
AND 7
JP NZ,LINELU2
LD A,L
SUB #20
LD L,A
JR C,LINELU2
LD A,H
ADD A,8
LD H,A
LINELU2 EX AF,AF'
SUB E
JR NC,LINELU3
ADD A,D
RLC C
JP NC,LINELU3
DEC L
LINELU3 EX AF,AF'
DJNZ LINELU1
RET
LINER CP H
LD L,A
JR C,LINERU
PUSH HL
CALL GET_ADR
POP DE
LD B,E
LD A,E
INC D
INC B
EX AF,AF'
LINERD1 LD A,(HL)
OR C
LD (HL),A
RRC C
JP NC,LINERD2
INC L
LINERD2 EX AF,AF'
SUB D
JR NC,LINERD4
ADD A,E
EX AF,AF'
LD A,H
DEC H
AND 7
JP NZ,LINERD3
LD A,L
SUB #20
LD L,A
JR C,LINERD3
LD A,H
ADD A,8
LD H,A
LINERD3 DJNZ LINERD1
RET
LINERD4 EX AF,AF'
DJNZ LINERD1
RET
LINERU PUSH HL
CALL GET_ADR
POP DE
LD B,D
LD A,D
INC E
INC B
EX AF,AF'
LINERU1 LD A,(HL)
OR C
LD (HL),A
LD A,H
DEC H
AND 7
JP NZ,LINERU2
LD A,L
SUB #20
LD L,A
JR C,LINERU2
LD A,H
ADD A,8
LD H,A
LINERU2 EX AF,AF'
SUB E
JR NC,LINERU3
ADD A,D
RRC C
JP NC,LINERU3
INC L
LINERU3 EX AF,AF'
DJNZ LINERU1
RET
GET_ADR LD A,#BF ;расчет адреса в экране
SUB D
LD D,A
SRL A
SCF
RRA
SRL A
XOR D
AND #F8
XOR D
LD H,A
LD A,E
RLCA
RLCA
RLCA
XOR D
AND #C7
XOR D
RLCA
RLCA
LD L,A
LD A,E
AND 7
INC A
LD C,B ;сохранение B
LD B,A
LD A,1
GETADR1 RRCA
DJNZ GETADR1
LD B,C ;восстановление B
LD C,A ;маска в c
RET