Код:
DEVICE ZXSPECTRUM128
MODULE MAIN
SPR_SIZE=#10
ORG #8000
START:
LD SP,#7FFF
LD HL,#BE00
LD A,H
LD I,A
IM 2
LD BC,#00BF
LD (HL),C
INC HL
DJNZ $-2
LD (HL),C
LD H,C
LD L,C
LD (HL),#C9
ST_LOOP:
EI
HALT
LD A,#07
OUT (#FE),A
LD HL,TEST_SPRITE
CURS_Y LD D,0 ; D=Y
CURS_X LD E,0 ; E=X
LD B,64 ; B=HEIGHT
LD C,SPR_SIZE ; C=LEN
CALL SPRITE_OUT
SUB A
OUT (#FE),A
JP ST_LOOP
SPRITE_OUT:
;-----------------------------------------------------
; Проверка левой и правой границ, расчет длинны строки
LD A,E
OR A
JP P,R_EDGE
NEG
LD (L_SKIP1),A
LD (L_SKIP2),A
NEG
ADD A,C
LD E,#00 ; Начало левой границы по X
EXX
LD IY,SP_CL2 ; Указатель на процедуру вывода коррекции слева
LD DE,PHASE2 ; Указатель на параметр фазы
JP LEN_CL
R_EDGE ADD A,C
SUB #20
JR C,NO_COR
LD (R_SKIP1),A
LD (R_SKIP2),A
NEG
ADD A,C
CP C ; Спрайт на всю ширину экрана?
EXX
LD IY,SP_CL3 ; Процедура вывода коррекции справа
LD DE,PHASE3 ; Указатель на параметр фазы
JR NZ,LEN_CL
EXX
NO_COR LD A,C ; Вывод без коррекции
EXX
LD IY,SP_CL1 ; Указатель на процедуру вывода без коррекции
LD DE,PHASE1 ; Указатель на параметр фазы
LEN_CL OR A
RET M ; Выход, если спрайт целиком за левой или правой границей экрана
ADD A,A ; Тут расчитываем длину спрайта для текущего метода вывода
SUB #40
NEG
LD IX,L_OUT1 ; Указатель на процедуру вывода LDI (HL-->DE)
LD C,A ; C'=A
LD B,#00
ADD IX,BC
EXX
;--------------------------------
; Проверка верхней границы экрана
LD A,D
CP #C1 ; Верхняя граница (-1..-63)
JR C,D_EDGE
NEG ; A - кол-во пропускаемых строк сверху
CP B
RET P ; Выход, если спрайт целиком за верхней границей экрана
LD D,A
PUSH DE
RRCA ; Расчитываем сколько строк атрибутов ушло за верхнюю границу
RRCA
RRCA
AND #1F
ADD A,D ; Пропускам D/8 строк
LD E,A
LD D,#00
PUSH BC
LD A,B
EXX
INC A
AND #07
LD (DE),A ; Помещаем код фазы в выбранную процедуру
EXX
LD B,#06
MULCYC SRL C
JR NC,NO_ADD
ADD HL,DE
NO_ADD SLA E
RL D
DJNZ MULCYC
POP AF
POP DE
SUB D
LD B,A
LD D,#40 ; Начало верхней границы на экране
JP (IY)
;-------------------------------
; Проверка нижней границы экрана
D_EDGE LD A,D
SUB #C0 ; Нижняя граница > 192 ?
RET NC ; Выход, если спрайт целиком за нижней границей экрана
ADD A,B
JR NC,CLC_DE ; Не корректируем высоту спрайта
SUB B
NEG
LD B,A
;-----------------------------
; Расчет экранного адреса
; E=X (#00-#1F), D=Y (#00-#BF)
CLC_DE LD A,D
AND #38
RLCA
RLCA
OR E
LD E,A
LD A,D
AND #C0
RRA
SCF
RRA
RRCA
XOR D
AND #F8
XOR D
LD D,A
;---------------------------------------
; Расчет фазы атрибутов для цикла вывода
LD A,B
EXX
INC A
AND #07
LD (DE),A ; Помещаем код фазы в выбранную процедуру
EXX
JP (IY)
;---------------------------------------------------
; Расчет в DE адрес атрибута, вывод строки атрибутов
AT_OUT LD A,D
RRCA
RRCA
RRCA
AND #0B
OR #50
LD D,A
;-----------------------------
; Вывод строки спрайта
L_OUT LD C,D
JP (IX)
L_OUT1 DUP 32
LDI
EDUP
RET
;-----------------------------
; Расчет следующего знакоместа
COR_DE LD A,E
SUB #E0
LD E,A
SBC A,A
AND #F8
ADD A,D
LD D,A
JP (IY)
;-----------------------------------------------------
; Процедура вывода на экран с атрибутами без коррекции
LOOP1 INC D
LD A,D
AND #07
JR Z,COR_DE
SP_CL1 LD A,E
CALL L_OUT
DEC DE ; Коррекция D, если Е > #FF
LD E,A
LD A,B
AND #07
PHASE1 EQU $+1
XOR #00
JR Z,A_OUT1
DJNZ LOOP1
RET
A_OUT1 PUSH DE
CALL AT_OUT
POP DE
DJNZ LOOP1
RET
;----------------------------------------------------------
; Процедура вывода на экран с атрибутами с коррекцией слева
LOOP2 INC D
LD A,D
AND #07
JR Z,COR_DE
SP_CL2 LD A,B
L_SKIP1 EQU $+1
LD BC,#0000 ; Переменная отступа слева
ADD HL,BC
LD B,E
CALL L_OUT
LD E,B ; При сдвиге влево D можно не корректировать
LD B,A
AND #07
PHASE2 EQU $+1
XOR #00
JR Z,A_OUT2
DJNZ LOOP2
RET
A_OUT2 PUSH DE
LD A,B
L_SKIP2 EQU $+1
LD BC,#0000
ADD HL,BC
LD B,A
CALL AT_OUT
POP DE
DJNZ LOOP2
RET
;-----------------------------------------------------------
; Процедура вывода на экран с атрибутами с коррекцией справа
LOOP3 INC D
LD A,D
AND #07
JR Z,COR_DE
SP_CL3 LD A,B
LD B,E
CALL L_OUT
DEC DE ; Коррекция D, если Е > #FF
LD E,B
R_SKIP1 EQU $+1
LD BC,#0000 ; Переменная отступа справа
ADD HL,BC
LD B,A
AND #07
PHASE3 EQU $+1
XOR #00
JR Z,A_OUT3
DJNZ LOOP3
RET
A_OUT3 PUSH DE
CALL AT_OUT
LD A,B
R_SKIP2 EQU $+1
LD BC,#0000
ADD HL,BC
LD B,A
POP DE
DJNZ LOOP3
RET
;----------------
; Тестовый спрайт
ORG #C000,#00
TEST_SPRITE:
DUP 3
DUP 4
DS SPR_SIZE,#55
DS SPR_SIZE,#AA
EDUP
DB #41
DS SPR_SIZE-2,#01
DB #41
DUP 4
DS SPR_SIZE,#F0
EDUP
DUP 4
DS SPR_SIZE,#0F
EDUP
DB #42
DS SPR_SIZE-2,#02
DB #42
DUP 4
DS SPR_SIZE,#55
DS SPR_SIZE,#AA
EDUP
DB #43
DS SPR_SIZE-2,#03
DB #43
DUP 4
DS SPR_SIZE,#F0
EDUP
DUP 4
DS SPR_SIZE,#0F
EDUP
DB #44
DS SPR_SIZE-2,#04
DB #44
DUP 4
DS SPR_SIZE,#55
DS SPR_SIZE,#AA
EDUP
DB #45
DS SPR_SIZE-2,#05
DB #45
DUP 4
DS SPR_SIZE,#F0
EDUP
DUP 4
DS SPR_SIZE,#0F
EDUP
DB #46
DS SPR_SIZE-2,#06
DB #46
DUP 4
DS SPR_SIZE,#55
DS SPR_SIZE,#AA
EDUP
DB #07
DS SPR_SIZE-2,#47
DB #07
DUP 4
DS SPR_SIZE,#F0
EDUP
DUP 4
DS SPR_SIZE,#0F
EDUP
DB #41
DS SPR_SIZE-2,#01
DB #41
EDUP
PAGE #00
SAVESNA "test.sna",START
ENDMODULE
---