Ну и мне захотелось и с окружностями разобраться в растровом представлении...
А это также реализует
Алгоритм Брезенхема построения окружности, и как везде пишут,
на алгоритм рисования линии он весьма похож, только в этом алгоритме строится дуга
окружности для первого квадранта, а координаты точек окружности для остальных
квадрантов получаются симметрично.
На каждом шаге алгоритма рассматриваются три пикселя, и из них выбирается наиболее
подходящий, путём сравнения расстояний от центра до выбранного пикселя с радиусом
окружности.
При этом, естественно, отталкиваются от уравнения окружности:
R^2 = X^2 + Y^2
Более подробно все выкладки можно посмотреть, к примеру,
вот здесь...
А на языке Васик этот алгоритм выглядит даже довольно просто:
Code: Select all
'--- "A Fast Bresenham Type Algorithm For Drawing Ellipses" by John Kennedy ---
DEFINT A-Z
SCREEN 12
px = 160
py = 120
r = 100
f = 1 - r
dx = 1
dy = -2 * r
x = 0
y = r
PSET (px, py - r)
PSET (px, py + r)
PSET (px - r, py)
PSET (px + r, py)
WHILE (x < y)
IF (f >= 0) THEN
y = y - 1
dy = dy + 2
f = f + dy
END IF
x = x + 1
dx = dx + 2
f = f + dx
PSET (px + x, py + y)
PSET (px + x, py - y)
PSET (px - x, py - y)
PSET (px - x, py + y)
PSET (px - y, py + x)
PSET (px - y, py - x)
PSET (px + y, py - x)
PSET (px + y, py + x)
WEND
Ну а теперь, как это реализовано на языке ассемблера внутри Васика нашего "Специалиста".
(Была у него такая
добавочка CIRCLE, разобраться с которой у меня в свое время руки так и не дошли...)
Code: Select all
;-----------------;
; CIRCLE SP-580 ;
;-----------------;
ORG 0000H
JMP START
RAD:DW 127;--- RADIUS
XPZ:DW 128;--- X-COORD.
Y_c:DB 128;--- Y-COORD.
X_c:DW 0000H
Z_p:DB 02H;--- OR with Screen Byte
START:
MVI A,1FH
CALL 0F80FH
CALL 0F80FH; Clear Screen
LHLD RAD; 0=>R=>127
DAD H; HL * 2
DAD H; HL * 4
DAD H; HL * 8
DAD H; HL * 16
DAD H; HL * 32
DAD H; HL * 64
DAD H; HL * 128
DAD H; HL * 256
DAD H; HL * 512
XCHG; HL<->DE
LHLD XPZ; 0=>X=>511
DAD D; HL = 512*R+X
CALL CIR;
MT0:CALL 0C803H; KBD
CPI 1BH; ESC?
JNZ MT0; NOT ESC...
JMP 0F800H; EXIT SYSTEM
NOP
NOP
K01:MOV A,C; AND Screen BIT;
CMA
ANA M
MOV M,A
RET
K02:MOV A,C; OR Screen BIT;
ORA M
MOV M,A
RET
K03:MOV A,C; XOR Screen BIT;
XRA M
MOV M,A
RET
ERR:
POP H; Restore HL;
POP H; Restore HL;
RET
M04:DB 00H;---- xx44h
DB 00H
M05:DB 00H
DB 00H
M06:DB 00H
DB 00H
M07:DB 00H
DB 00H
M08:DB 00H
DB 00H
M09:DB 00H
DB 00H
MASK:
DB 00H;---- 1_1_1_1 1_1_1_1b
;-- PLOT X,Y,Z
PLOT:
PUSH H; Save HL
LHLD X_c; X-coord;
PUSH H; HL = X-coord;
LXI D,0FE80H ; DE = -384
DAD D; HL = X - 384
JC ERR; ----- error: X > 384;
POP H; HL = X-coord;
MOV A,L
ANI 07H; 0000.0111b 8-lsb bits
DAD H; HL * 2
DAD H; HL * 4
DAD H; HL * 8
DAD H; HL * 16
DAD H; HL * 32
LXI D,9000H; Screen 1-st byte
DAD D; 9000H + HL * 32
MOV C,A
LDA Y_c; Y-coord;
MOV L,A; HL - Byte at X,Y - coord;
MVI A,01H
SBT:RRC; Set bit in Byte at X,Y - coord;
DCR C
JP SBT
CALL PUT
POP H; Restore HL;
RET
PUT:MOV C,A
LDA Z_p
CPI 01H
JZ K01
CPI 02H
JZ K02
CPI 03H
JZ K03
RET
; PLOT 512* R + X, Y, Z:' (0=>R=>63)
; PLOT -65536 + 512 * R + X, Y, Z:' (64=>R=>127)
; 0=>R=>127: 512 * 127 = 0FE00h
; 0=>X=>511: 511d = 1FFh - 1 byte + 1 hi bit.
; 0=>Y=>255
;
CIR:
NOP; HL = 512*R+X-coord;
XRA A; A = 0; c = 0
MOV B,A; B = 0;
MOV A,H;
RAR; c765.4321->0 - msb X
MOV C,A; C = H/2 = R;
MOV A,B; B = 0;
RAL; 6543.210c<-7
MOV H,A; xxx_.L - 0=>X=>511
SHLD M04;
MOV H,B; H = B = 0;
MOV L,C; L = R; 0=>R=>127;
SHLD M06;
LDA Y_c; Y-coord: 0=>Y=>255;
MOV L,A; H = B = 0; L = Y ;
SHLD M05
MOV L,B; L = B = 00h;
SHLD M08; = 0000h;
SHLD M09; = 0000h;
DCR H
MOV A,B
SUB C
MOV L,A
SHLD M07
DAD H
MVI C,03H
DAD B
PUSH H
M0B:LDA MASK
LXI H,TB1;---
CALL M0E
POP H
PUSH H
DAD H
LHLD M08
JC M0C
XCHG
LXI H,M06
DCR M
LHLD M07
INX H
SHLD M07
DAD D
M0C:DAD H
DAD H
LXI D,0006H;
DAD D
POP D
DAD D
PUSH H
LHLD M09
DCX H
SHLD M09
LXI H,M08
INR M
LDA M06
CMP M
JC M0D
PUSH PSW
MOV A,B
LXI H,TB2;---
CALL M0E
POP PSW
JNZ M0B
M0D:POP H
NOP
RET
M0E:RLC
MOV B,A
MVI C,04H
M0F:MOV A,M
STA M10+1; mod. Addr.low;
INX H
MOV A,M
STA M11+1; mod. Addr.low;
MOV A,B
RRC
RRC
MOV B,A
JC M13
PUSH H
;--------v low;
M10:LHLD M09
XCHG
LHLD M04
DAD D
SHLD X_c
LXI D,0FE80H; -384;
DAD D
JC M12
;--------v low;
M11:LHLD M06
XCHG
LHLD M05
DAD D
MOV A,L
STA Y_c
LXI D,0FF00H; -256;
DAD D
PUSH B
CNC PLOT; EQU 17D8H;
POP B
M12:POP H
M13:DCR C
JNZ M0F
RET
NOP
NOP
TB1:DB 48H;
DB 4EH;
DB 4AH;
DB 4CH;
TB2:DB 48H;
DB 4CH;
DB 4AH;
DB 4EH;
DB 48H;
END
Сразу предупреждаю, что программа самомодифицирующаяся, и с другого адреса её запустить трудно,
поскольку в теле есть таблица, привязанная к конкретным смещениям.
Я смещения пересчитывать заленился и выровнял NOP-ами таблицу на подходящие адреса.
В результате получается вот что:
Как я и говорил тут ранее:
Lavr wrote:А у меня на зелёном венгерском мониторе "Орион" круг был просто идеальным!
...круг выходил совершенно правильным кругом на печать моим любимым принтером
тех времен - УВВПЧ. То есть имел место полный "ВизВиг"...
А на
ассемблере 6502 код для рисования окружностей у меня вышел следующим:
Code: Select all
;*******************************************
; Draw circles using Bresenham's algorithm *
;*******************************************
;--- ZP base address of data area
*= $0020; Center Point X;
l_XC:
*= $0021
h_XC:
*= $0022; Center Point Y;
l_YC:
*= $0023
h_YC:
*= $0024; radius (1 byte)
lRAD:
*= $0025
hRAD:
*= $0026; plot point
l_XP:
*= $0027;
h_XP:
*= $0028;
l_YP:
*= $0029;
h_YP:
*= $002a; x,y intermediate
l_X1:
*= $002b;
h_X1:
*= $002c;
l_Y1:
*= $002d;
h_Y1:
*= $002e; difference
l_FF:
*= $002f;
h_FF:
*= $0030; diff x
l_FX:
*= $0031;
h_FX:
*= $0032; diff y
l_FY:
*= $0033;
h_FY:
*= $0034;
l_XY:
*= $0035
h_XY:
*= $0036
rCOL:
*= $0600 ;
start:
LDA #16; Center low;
STA l_XC; XL = 16
STA l_YC; YL = 16
LDA #0; Center high
STA h_XC; XH = 00
STA h_YC; YH = 00
STA hRAD; RADH = 00
loop:
LDA $fe ; RND Radius low;
AND #$0F; A <= 15
STA lRAD; RND RADL = A <=15
LDA $fe ; A = RND;
STA rCOL; COLOR = RND;
JSR CIRCLE; CIRCLE(XC,YC-lRAD)
JMP loop; jump CYCLE ;
; ----------------------------------
; CIRCLE: Draw a circle around the
; center XC/YC with radius in lRAD.
*= $c000
CIRCLE:
lda lRAD ; get Radius
bne _C1
lda l_XC ; if lRAD=0, plot center point and exit
sta l_XP ; move center point to plot point var
lda h_XC
sta h_XP
lda l_YC
sta l_YP
lda h_YC
sta h_YP
jmp PSET ; Plot as a point and exit
; int y = radius;
_C1:
lda lRAD ; 8 bit radius - can be expanded to 16 bit
sta l_Y1
ldx #$00
stx h_Y1
; int x = 0;
stx l_X1;
stx h_X1;
; if using 16 bit radius, this code
; section will need modifications
; int f = 1 - radius;
sec
lda #$01
sbc lRAD
sta l_FF
ldx #$00
stx h_FF
bcs _C2
dec h_FF
; int ddF_x = 1;
_C2:
lda #$01
sta l_FX
ldx #$00
stx h_FX
; if using 16 bit radius, this code section
; will need modifications also
; int ddF_y = -2 * radius;
stx h_FY
lda lRAD
asl ; *2
sta l_FY
rol h_FY
lda l_FY
EOR #$FF
sta l_FY
lda h_FY
EOR #$FF
sta h_FY
inc l_FY
bne _C3
inc h_FY
; tgi_setpixel(xC, yC + y);
_C3:
lda l_XC
sta l_XP
lda h_XC
sta h_XP
clc
lda l_YC
adc l_Y1
sta l_YP
lda h_YC
adc h_Y1
sta h_YP
jsr PSET
; tgi_setpixel(xC, yC - y);
sec
lda l_YC
sbc l_Y1
sta l_YP
lda h_YC
sbc h_Y1
sta h_YP
jsr PSET
; tgi_setpixel(xC + y, yC);
clc
lda l_XC
adc l_Y1
sta l_XP
lda h_XC
adc h_Y1
sta h_XP
lda l_YC
sta l_YP
lda h_YC
sta h_YP
jsr PSET
; tgi_setpixel(xC - y, yC);
sec
lda l_XC
sbc l_Y1
sta l_XP
lda h_XC
sbc h_Y1
sta h_XP
jsr PSET
_CLOOP:
; while (x < y) { ; calculate next plot step
sec
lda l_X1
sbc l_Y1
lda h_X1
sbc h_Y1
bcc _C4 ; x<y
rts
_C4:
lda h_FF
bmi _C6
lda l_Y1
bne _C5
dec h_Y1
_C5:
dec l_Y1
clc
lda l_FY
adc #$02
sta l_FY
tax
lda h_FY
adc #$00
sta h_FY
tay
clc
txa
adc l_FF
sta l_FF
tya
ADC h_FF
sta h_FF
_C6:
inc l_X1
bne _C7
inc h_X1
_C7:
clc
lda l_FX
adc #$02
sta l_FX
tax
lda h_FX
adc #$00
sta h_FX
tay
clc
txa
adc l_FF
sta l_FF
tya
ADC h_FF
sta h_FF
; computations done - now plot 8 Octants
; tgi_setpixel(xC + x, yC + y);
clc
lda l_XC
adc l_X1
sta l_XP
pha
lda h_XC
adc h_X1
sta h_XP
pha
clc
lda l_YC
adc l_Y1
sta l_YP
lda h_YC
adc h_Y1
sta h_YP
jsr PSET
; tgi_setpixel(xC - x, yC + y);
sec
lda l_XC
sbc l_X1
sta l_XP
lda h_XC
sbc h_X1
sta h_XP
jsr PSET
; tgi_setpixel(xC - x, yC - y);
sec
lda l_YC
sbc l_Y1
sta l_YP
lda h_YC
sbc h_Y1
sta h_YP
jsr PSET
; tgi_setpixel(xC + x, yC - y);
pla
sta h_XP
pla
sta l_XP
jsr PSET
; tgi_setpixel(xC + y, yC + x);
clc
lda l_XC
adc l_Y1
sta l_XP
pha
lda h_XC
adc h_Y1
sta h_XP
pha
clc
lda l_YC
adc l_X1
sta l_YP
lda h_YC
adc h_X1
sta h_YP
jsr PSET
; tgi_setpixel(xC - y, yC + x);
sec
lda l_XC
sbc l_Y1
sta l_XP
lda h_XC
sbc h_Y1
sta h_XP
jsr PSET
; tgi_setpixel(xC - y, yC - x);
sec
lda l_YC
sbc l_X1
sta l_YP
lda h_YC
sbc h_X1
sta h_YP
jsr PSET
; tgi_setpixel(xC + x, yC - y);
pla
sta h_XP
pla
sta l_XP
jsr PSET
jmp _CLOOP
; ------------------------------------------------
; PSET: Test pixel @ XP,YP and plot it on screen
PSET:
LDA l_YP
ASL; 2* l_YP ;
TAX; X = 2* l_YP ;
LDA offs,x
INX
CLC
ADC l_XP
STA l_XY
LDA offs,x
ADC #$02
STA h_XY
LDX #0
LDA rCOL
STA ($34,X)
RTS
offs:
dcb $00,$00
dcb $20,$00
dcb $40,$00
dcb $60,$00
dcb $80,$00
dcb $a0,$00
dcb $c0,$00
dcb $e0,$00
dcb $00,$01
dcb $20,$01
dcb $40,$01
dcb $60,$01
dcb $80,$01
dcb $a0,$01
dcb $c0,$01
dcb $e0,$01
dcb $00,$02
dcb $20,$02
dcb $40,$02
dcb $60,$02
dcb $80,$02
dcb $a0,$02
dcb $c0,$02
dcb $e0,$02
dcb $00,$03
dcb $20,$03
dcb $40,$03
dcb $60,$03
dcb $80,$03
dcb $a0,$03
dcb $c0,$03
dcb $e0,$03
;------end-------------------------
И
в результате работы этого кода получаются вот такие
результаты:
------------