PDA

Просмотр полной версии : Алгоритмы рисования окружности и OVER 1



Oleg N. Cher
16.09.2015, 22:26
Столкнулся с такой проблемой существующих процедур рисования окружности, которые можно, в частности, найти здесь на форуме. Например, алгоритм из "Библии демомейкера" (zx-pk.ru/showthread.php?t=19727) в OVER 1 рисует такую окружность:

Oleg N. Cher
16.09.2015, 22:27
То есть некоторые точки рисуются по два раза. И даже если вообще никто не рисует окружности в режиме OVER 1, то всё равно это - потеря производительности.

Стандартная ПЗУ'шная процедура такой проблемы не имеет.

Хотелось бы найти быструю и корректную в этом смысле процедуру. Что посоветуете?

shurik-ua
16.09.2015, 22:33
Что посоветуете?

http://www.mari-el.ru/mmlab/home/kg/Lection5/5.html

Oleg N. Cher
16.09.2015, 22:38
Есть у меня ещё одна процедура (не помню откуда брал), интересная тем, что радиус можно задавать двухбайтовым числом. И можно рисовать за пределами экрана.


void Basic_CIRCLEW_EI (unsigned char cx, unsigned char cy, int radius) __naked {
__asm
LD IY, #0x5C3A
POP DE
POP BC ; BC = YX
POP HL ; HL = radius
PUSH HL
PUSH BC
PUSH DE
LD A, H
OR L
RET Z
BIT 7, H
RET NZ
PUSH IX
DI
LD D, #0
LD E, C
LD C, B
LD B, D
PUSH DE
LD DE, #0
PUSH DE
PUSH BC
PUSH HL
LD IX, #0
ADD IX, SP
PUSH HL
EXX
POP HL
ADD HL, HL
EX DE, HL
LD HL, #3
AND A
SBC HL, DE
EXX
JR ENT1$
CIRCLOOP1$:
AND A
SBC HL, DE
JP M, EXT1$
POP DE
POP HL
ADD HL, DE
EX DE, HL
POP BC
POP HL
ADD HL, BC
LD SP, IX
CALL WRAP1$
POP BC
POP HL
POP DE
ADD HL, DE
EX DE, HL
POP HL
ADD HL, BC
LD SP, IX
CALL WRAP1$
POP DE
POP HL
AND A
SBC HL, DE
EX DE, HL
POP BC
POP HL
AND A
SBC HL, BC
LD SP, IX
CALL WRAP1$
POP BC
POP HL
POP DE
AND A
SBC HL, DE
EX DE, HL
POP HL
AND A
SBC HL, BC
LD SP, IX
CALL WRAP1$
ENT1$:
POP DE
POP HL
ADD HL, DE
EX DE, HL
POP BC
POP HL
AND A
SBC HL, BC
LD SP, IX
CALL WRAP1$
POP BC
POP HL
POP DE
ADD HL, DE
EX DE, HL
POP HL
AND A
SBC HL, BC
LD SP, IX
CALL WRAP1$
POP DE
POP HL
AND A
SBC HL, DE
EX DE, HL
POP BC
POP HL
ADD HL, BC
LD SP, IX
CALL WRAP1$
POP BC
POP HL
POP DE
LD (POSITIV1$+1), DE
AND A
SBC HL, DE
EX DE, HL
POP HL
ADD HL, BC
LD SP, IX
CALL WRAP1$
EXX
EX DE, HL
BIT 7, D
JR Z, POSITIV1$
LD HL, (POSITIV1$+1)
ADD HL, HL
ADD HL, HL
LD BC, #6
JR CALCDONE1$
POSITIV1$:
LD HL, #0
POP BC
DEC BC
PUSH BC
AND A
SBC HL, BC
ADD HL, HL
ADD HL, HL
LD BC, #0xA
CALCDONE1$:
ADD HL, BC
ADD HL, DE
EXX
POP HL
POP DE
POP DE
INC DE
PUSH DE
LD SP, IX
JP CIRCLOOP1$
EXT1$:
LD HL, #8
ADD HL, SP
LD SP, HL
POP IX
EI
RET
WRAP1$:
LD A, D
OR A
RET NZ
LD A, H
OR A
RET NZ
LD A, E
CP #0xB0
RET NC
LD B, E
LD C, L
JP 0x22E5
__endasm;
}

Но у неё та же проблема:

Oleg N. Cher
17.09.2015, 00:01
shurik-ua, спасибо конечно. Но уточню: мне нужна не теория и алгоритм на псевдобейсике, а нормальный отлаженный код на ассемблере Z80. Или совет как пофиксить упомянутые выше процедуры.

Вторую хотелось бы отладить особенно, потому что она редкостная - большинство процедур, которые я здесь встречал, имеют однобайтовые аргументы.

s_kosorev
17.09.2015, 00:17
Возможно рисует по две точки как раз из за упрощения/ускорения рисования, просто пожертвовали лишними проверками или точностью алгоритма

Reobne
17.09.2015, 06:07
Мы хотим получить круто оптимизированный код на ассемблере, чтобы он прямо пиксель в пиксель повторял результат рисования бейсиковского круга? Или можно немножко переставить пикселки в углах, главное чтобы два раза в одном месте не рисовалось, и смотрелось правильно?

Вход определим. X,Y,Z- целые? байт? слово(2 байта) со знаком?
Результат:
На весь экран? (256x192)
Круг частично выходит за экран?
Атрибуты красим? (инк, папер, яркость мигание)

Как опции можно сделать круги с заливкой. Нужно?

Destr
17.09.2015, 07:53
Есть у меня ещё одна процедура (не помню откуда брал), интересная тем, что радиус можно задавать двухбайтовым числом.

Или совет как пофиксить упомянутые выше процедуры.
В этой процедуре последнюю точку не печатать (если уже была).
Например так (новая подпрограмма печати точки)


WRAP1
LD A, D
OR A
RET NZ
LD A, E
CP #B0
RET NC
LD A, H
OR A
RET NZ
LD B, E
LD C, L
WRAP2 LD HL,0
LD (WRAP2+1),BC
SBC HL,BC
RET Z
JP #22E5

Oleg N. Cher
17.09.2015, 19:09
Фикс Destr'а рабочий и, в принципе, меня устраивает. Благодарю!


Мы хотим получить круто оптимизированный код на ассемблере, чтобы он прямо пиксель в пиксель повторял результат рисования бейсиковского круга? Или можно немножко переставить пикселки в углах, главное чтобы два раза в одном месте не рисовалось, и смотрелось правильно?Думаю, можно.


Вход определим. X,Y,Z- целые? байт? слово(2 байта) со знаком?
Результат:
На весь экран? (256x192)
Круг частично выходит за экран?
Атрибуты красим? (инк, папер, яркость мигание)

Как опции можно сделать круги с заливкой. Нужно?Сейчас у меня просто стоит задача получить хоть какую-то окружность в OVER 1. Но в общем-то:

1. Для библиотеки Basic (ZXDev) нужна процедура окружности. CIRCLEROM там уже есть. CIRCLE задумана как то же самое, но быстрый вариант (все параметры - беззнаковые байты) и не позволяет рисовать за пределами экрана. CIRCLEW - то же самое, но все параметры - слова со знаком. Такой процедуры я не нашёл, поэтому пока удовольствовался процедурой, где координаты - байты без знака, а радиус - слово со знаком. Она умеет рисовать за пределами экрана не всю окружность, а только её часть.

Можно поспорить с тем, нужна ли CIRCLEW непосредственно в библиотеке Basic, но уже пускай будет - по аналогии с RND (результат - байт) и RNDW (результат - слово).

2. Для библиотеки Gfx, которую я недавно начал формировать, пригодились бы и другие варианты окружности, в т.ч. и залитой. Так что буду благодарен.

Sergey
17.09.2015, 22:07
Не могу сказать, сколько раз рисуются точки, - это, вообще, странно слышать, что одна точка несколько раз рисуется. Зачем, также, этот кривой ПЗУшный алгоритм? - разве он не через DRAW рисует? - окружности с малыми радиусами получаются КРИВЫЕ (либо у меня другой бейсик зашит?!).
Рекомендую алгоритм Мичнера. Мне его окружности больше глаз радуют. Сам пока использую сишную процедуру, на асме только рисование точек (под TS-Config). Но давненько хотелось целиком на асм переложить. Может, после работы займусь.


/*--------------------------------------------------- V_MIcirc
* Генерирует 1/8 окружности по алгоритму Мичнера
*/

void V_MIcirc (int xc, int yc, int r, int pixel)
{ int x, y, d;
x= 0; y= r; d= 5 - 2*r;
while (x < y) {
Pixel_circle(xc, yc, x, y, pixel,MyVPage);
if (d < 0) d= d + 4*x + 6; else {
d= d + 4*(x-y) + 10; --y;
};
++x;
};
if (x == y) Pixel_circle(xc, yc, x, y, pixel, MyVPage);
} /* V_MIcirc */


void Pixel_circle(int xc, int yc, int x, int y, int pixel, int pg) __naked
{ xc,yc,x,y,pixel,pg;
__asm
di
pop af
pop hl ; xc
ld (5$+1),hl
ex de,hl
pop hl
ld (9$+1),hl ; yc
pop hl
ld (10$+1),hl
ld b,h
ld c,l ; x
pop hl
ld (11$+1),hl ; y
pop hl
ld a,l
ld (7$+1),a
pop hl
ld a,l
ld (6$+1),a
ld hl,#-14
add hl,sp
ld sp,hl
ei

; plot8(xc+x, yc+y);
ex de,hl
add hl,bc
ex de,hl
9$:
ld hl,#0 ; yc val
11$:
ld bc,#0 ; y val
add hl,bc
call 2$
; plot8(xc+y, yc+x);
5$: ld hl,#0 ; xc val
ld bc,(11$+1)
add hl,bc
ex de,hl
ld hl,(9$+1)
10$: ld bc,#0 ; x val
add hl,bc
call 2$
; plot8(xc+y, yc-x);
ld hl,(5$+1)
ld bc,(11$+1)
add hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(10$+1)
or a,a
sbc hl,bc
call 2$
; plot8(xc+x, yc-y);
ld hl,(5$+1)
ld bc,(10$+1)
add hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(11$+1)
or a,a
sbc hl,bc
call 2$
; plot8(xc-x, yc-y);
ld hl,(5$+1)
ld bc,(10$+1)
or a,a
sbc hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(11$+1)
or a,a
sbc hl,bc
call 2$
; plot8(xc-y, yc-x);
ld hl,(5$+1)
ld bc,(11$+1)
or a,a
sbc hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(10$+1)
or a,a
sbc hl,bc
call 2$
; plot8(xc-y, yc+x);
ld hl,(5$+1)
ld bc,(11$+1)
or a,a
sbc hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(10$+1)
add hl,bc
call 2$
; plot8(xc-x, yc+y);
ld hl,(5$+1)
ld bc,(10$+1)
or a,a
sbc hl,bc
ex de,hl
ld hl,(9$+1)
ld bc,(11$+1)
add hl,bc
call 2$
ei
ret

2$:
;--- plot routine --- для 0-го окна.
; DE = X
; HL = Y
;--- rom off ---
di
ld a,#0x0E ; // RAM|NoMAP|WE|BASIC-128
ld bc,#0x21af ;_MemConfig
out (c),a
;---------------
add hl,hl
ld a,l
add a,d
and a,#0x3f
ld d,a
add hl,hl
add hl,hl

ld a,h
6$: add a,#0x00 ; сюда при чтении аргументов занести номер видеостраницы.
ld b,#0x10 ; 0-е окно.
out (c),a
7$: ld a,#0x00 ; сюда при чтении аргументов занести значение цвета.
ld (de),a
;--- rom on ---
ld a,#0x04 ; // ROM|MAP|WP|BASIC-128
ld b,#0x21 ; _MemConfig
out (c),a
ld b,#0x10
ld a,#3
out (c),a
ei
;---------------
ret
__endasm;
}

Sergey
18.09.2015, 08:33
Вот Мичнер в более приятной для Олега паскалевидной форме: ;)

procedure bres_circle(xc,yc,r:interger):
var x,y,d:integer:
procedure sim(x,y;integer);
begin
putpixel(x+xc,y+yc,White);
putpixel(x+xc,-y+yc,White);
putpixel(-x+xc,-y+yc,White);
putpixel(-x+xc,y+yc,White);
putpixel(y+xc,x+yc,White);
putpixel(y+xc,-x+yc,White);
putpixel(-y+xc,-x+yc,White);
putpixel(-y+xc,x+yc,White);
end;
begin
d:=3-2*y;
x:=0;
y:=r;
while(x <= y) do
begin
sim(x,y);
if d<0 then d:=d+4*x+6
else begin
d:=d+4*(x-y)+10;
dec(y)
end;
inc(x)
end;
end;

Кстати, воспринимается полегче, чем Си.

Oleg N. Cher
18.09.2015, 22:15
Не могу сказать, сколько раз рисуются точки, - это, вообще, странно слышать, что одна точка несколько раз рисуется.Вот-вот, а я-то как удивился. :)


Зачем, также, этот кривой ПЗУшный алгоритм?Разве что для полного соответствия ZX-Бейсику или экономии памяти. Ну и реверанс в сторону Ревю и книжек по графике, где окружность предлагалось рисовать только алгоритмом из ПЗУ.


Рекомендую алгоритм Мичнера. Мне его окружности больше глаз радуют.Спасибо! Полезно и для не-ZX. Если будет целиком в машкоде (или адаптированный для Спека) — буду рад увидеть код.

Sergey
18.09.2015, 22:22
Хотелось бы найти быструю и корректную в этом смысле процедуру. Что посоветуете?
Решил пока воздержаться от изобретания велосипеда, - вот нашёл:
http://icereijo.com/a-circle-algorithm-for-zx-spectrum/
там и исходники, и тапка, и видео даже.

Sergey
21.09.2015, 08:06
То есть некоторые точки рисуются по два раза. И даже если вообще никто не рисует окружности в режиме OVER 1, то всё равно это - потеря производительности.
Эврика. Выбранная тобой процедура, используя свойства симметрии, рисует точки по октетам. При одной из координат равной 0, количество вариантов расположения точек вырождается до 4-х: смещения от оси симметрии равны +0/-0. Поэтому точки при этом рисуются на одном и том же месте. Избежать этого можно, если для случаев x=0 / y=0 сделать специальные п/п рисования точек.

GM BIT
22.09.2015, 07:00
а как включить режим OVER 1 для #22Е5 через код?

Destr
22.09.2015, 08:16
а как включить режим OVER 1 для #22Е5 через код?
На скорую руку вот так включал #5C91=1
Но это без передачи управления бейсику, иначе он обратно вернёт.

Sergey
04.10.2015, 10:32
Пробуйте. Не должно быть повторных точек. Учитывает края экрана.
Расплата: 14 и 20 тактов на точку соответственно.

void circle3(unsigned char cx, unsigned char cy, unsigned char r) __naked
{ cx,cy,r;
__asm
ld hl,#2
add hl,sp
ld b,(hl)
inc hl
ld c,(hl)
inc hl
ld l,(hl)

ld (xcyc+1),bc ; b = x, c = y. , переменная в коде команды.
xor a,a
ld c,l ; y = r;
ld b,a ; x = 0;
ld h,a
add hl,hl
ld de,#5
ex de,hl
or a,a
sbc hl,de
ld (var_d+1),hl ; d = 5 - 2r;

loop:
ld a,b
cp c
jp c,q0
call z,pixels
ret
q0: call pixels
var_d:
ld de,#0 ; _d переменная в коде команды.
bit 7,d
jp z,q1
; d < 0:
ld h,#0
ld l,b
add hl,hl
add hl,hl
add hl,de
ld de,#6
add hl,de
ld (var_d+1),hl
inc b ; ++x
jp loop

q1: ld a,b ; x-y
sub c
ld l,a
sbc a,a
ld h,a ; sign is extended
add hl,hl
add hl,hl
add hl,de
q3: ld de,#10
add hl,de
ld (var_d+1),hl
dec c ; --y
inc b ; ++x
jp loop

pixels:
;xc+x, yc+y
xcyc: ld hl,#0 ;(xcyc)
ld a,b
or a,a
jp z,p1
add a,h
jp c,p1
ld d,a
ld a,c
or a,a
jp z,p1
add a,l
cp a,#192
jp nc,p1
ld e,a
call plote
; xc+x, yc-y
ld hl,(xcyc+1)
p1: ld a,b
or a,a
jp z,p2
add a,h
jp c,p2
ld d,a
ld a,l
sub a,c
jp c,p2
ld e,a
call plote
; xc-x, yc-y
ld hl,(xcyc+1)
p2: ld a,h
sub a,b
jp c,p3
ld d,a
ld a,l
sub a,c
jp c,p3
ld e,a
call plote
; xc-x, yc+y
ld hl,(xcyc+1)
p3: ld a,h
sub a,b
jp c,p4
ld d,a
ld a,l
or a,a
jp z,p4
add a,c
cp #192
jp nc,p4
ld e,a
call plote
; xc+y, yc+x
ld hl,(xcyc+1)
p4: ld a,h
or a,a
jp z,p5
add a,c
jp c,p5
ld d,a
ld a,b
or a,a
jp z,p5
add a,l
cp #192
jp nc,p5
ld e,a
call plote
; xc+y, yc-x
ld hl,(xcyc+1)
p5: ld a,c
or a,a
jp z,p6
add a,h
jr c,p6
ld d,a
ld a,l
sub a,b
jr c,p6
ld e,a
call plote
; xc-y, yc-x
ld hl,(xcyc+1)
p6: ld a,h
sub a,c
jr c,p7
ld d,a
ld a,l
sub a,b
jr c,p7
ld e,a
call plote
; xc-y, yc+x
ld hl,(xcyc+1)
p7: ld a,h
sub a,c
ret c
ld d,a
ld a,b
or a,a
ret z
add a,l
ret c
ld e,a
call plote
ret
plote: ; (C)SATSOFT, Body #07.
push bc
; LD D,10 ;КООРДИНАТА Х
; LD E,11 ;КООРДИНАТА Y
LD A,#0xAF ;РАСЧЕТ АДРЕСА ПО КООРДИНАТАМ
SUB E
jp c,exit
LD E,A
AND A
RRA
SCF
RRA
AND A
RRA
XOR A,E
AND #0xF8
XOR A,E
LD H,A
LD A,D
RLCA
RLCA
RLCA
XOR A,E
AND #0xC7
XOR A,E
RLCA
RLCA
LD L,A
LD A,D ;КООРДИНАТА Х
AND #0x07 ;МАСКИРОВАНИЕ
LD B,A ;ОСТАТОК ОТ ДЕЛЕНИЯ Х НА 8
INC B ;+1
LD A,#0xFE ;ВВЕЛИ БАЙТ 11111110
PLOOP:
RRCA ;ВРАЩЕНИЕ N+1 РАЗ
DJNZ PLOOP
LD B,#0xFF ;ИНВЕРСИЯ,ЧТОБЫ ПЕЧАТЬ ТОЧКИ БЫЛА ЧЕРНЫМ
XOR A,B ;ПО БЕЛОМУ
LD B,A ;ЗАПОМНИЛИ В РЕГИСТРЕ 'B'
LD A,(HL) ;В 'А' ГРУЗИМ ЗНАЧЕНИЕ ИЗ ЭКРАНА
OR A,B ;ВКЛЮЧЕМ ТРЕБУЕМЫЙ БИТ
LD (HL),A ;ГРУЗИМ В ЭКРАН ПОЛУЧЕННЫЙ РЕЗУЛЬТАТ
exit:
pop bc
RET ;ВЫХОД ИЗ ПРОЦЕДУРЫ :)

__endasm;
}

Oleg N. Cher
06.10.2015, 14:11
Как всё-таки можно зафиксить "библейский" алгоритм рисования окружности под OVER 1 ? (см. первый пост темы).


;--------------------------------------------------
;9. Окружность, на входе в HL,127+87*256 (x=127, y=87)
;--------------------------------------------------

CIRCLE LD HL,127+87*256 ;(x=127, y=87)
LD D,50 ;r=50
LD C,0: LD B,D
LOOP CALL DOT ;sector 1
LD A,B: NEG: LD B,A: CALL DOT ;sector 4
LD A,C: NEG: LD C,A: CALL DOT ;sector 5
LD A,B: NEG: LD B,A: CALL DOT ;sector 8
LD A,C: LD C,B: LD B,A: CALL DOT ;sector 3
LD A,C: NEG: LD C,A: CALL DOT ;sector 6
LD A,B: NEG: LD B,A: CALL DOT ;sector 7
LD A,C: NEG: LD C,A: CALL DOT ;sector 8
LD A,C: LD C,B: LD B,A
INC C
LD A,D: SUB C: LD D,A: JR NC,LOOP
DEC B
LD A,D: ADD A,B: LD D,A
LD A,B: CP C: JR NC,LOOP
RET

DOT PUSH HL: PUSH DE: PUSH BC
LD A,H: ADD A,B: LD B,A
LD A,L: ADD A,C: LD C,A
CALL #22e5
POP bc: POP DE: POP HL
RET
Я протестировал его с фиксом, предложенным Destr, - запоминать координаты предыдущей точки и если текущие совпадают с ними, то не рисовать.


DOT PUSH HL: PUSH DE: PUSH BC
LD A,H: ADD A,B: LD B,A
LD A,L: ADD A,C: LD C,A
WRAP ; fixed for OVER 1 by Destr
LD HL,#ffff: LD (WRAP+1),BC
AND A: SBC HL,BC: CALL NZ,#22e5
POP bc: POP DE: POP HL
RETНе получается. Причина - некоторые (но не все) точки по одним координатам рисуются не подряд.

Зафиксить бы, братцы, - уж больно процедурка хороша. Компактная такая.

jerri
06.10.2015, 18:09
у тебя есть два варианта рисования точек в круге.

1ый когда количество точек четное
2ой когда оно нечетное
в варианте с четным количеством все будет ОК
в варианте с нечетным последняя точка будет рисоваться 2 раза.

Reobne
06.10.2015, 19:18
Oleg N. Cher, Тупо сделал заплатку.

;--------------------------------------------------
;9. Окружность, на входе в HL,127+87*256 (x=127, y=87)
;--------------------------------------------------

CIRCLE LD HL,127+87*256 ;(x=127, y=87)
LD D,56 ;r=50
LD C,D: LD B,0
CALL DOT
LD A,C: NEG: LD C,A: CALL DOT
LD B,C: LD C,0
CALL DOT
LD A,B: NEG: LD B,A: CALL DOT
jr DLOOP
LOOP CALL DOT ;sector 1
LD A,B: NEG: LD B,A: CALL DOT ;sector 4
LD A,C: NEG: LD C,A: CALL DOT ;sector 5
LD A,B: NEG: LD B,A: CALL DOT ;sector 8
HLOOP
LD A,C: LD C,B: LD B,A: CALL DOT ;sector 3
LD A,C: NEG: LD C,A: CALL DOT ;sector 6
LD A,B: NEG: LD B,A: CALL DOT ;sector 7
LD A,C: NEG: LD C,A: CALL DOT ;sector 8
LD A,C: LD C,B: LD B,A
DLOOP
INC C
LD A,D: SUB C: LD D,A: JR NC,LOOP
DEC B
LD A,D: ADD A,B: LD D,A
LD A,C: CP B: JR C,LOOP
JP Z,HLOOP
RET

DOT PUSH HL: PUSH DE: PUSH BC
LD A,H: ADD A,B: LD B,A
LD A,L: ADD A,C: LD C,A
CALL #22e5
POP bc: POP DE: POP HL
RET


---------- Post added at 23:18 ---------- Previous post was at 23:13 ----------

JP Z,HLOOP можно поменять на JR Z,HLOOP
jr DLOOP можно убрать.( тупо отрисуются лишние 8 точек, зато экономия байтов :) )
Это по вкусу.

Oleg N. Cher
06.10.2015, 22:11
Спасибо! Отличное решение, Reobne. И оно оптимальнее исходного по скорости (за счёт отказа от рисования лишних точек). А байтики - то уже такое, процедурка всё равно некрупная. Теперь меня в принципе всё устраивает. Но маленькое отличие кружков в OVER 0 и OVER 1 всё-таки есть. См. самый маленький, как он отличается (справа - OVER 1):

Oleg N. Cher
06.10.2015, 22:21
P.S. У месье гурманов есть какие-то претензии к красивости полученных "библейским" способом окружностей?

Reobne
07.10.2015, 02:51
Ещё заплатки сделал, чтобы R=0 и R=1 были нормальные.

;--------------------------------------------------
;9. Окружность, на входе в HL,127+87*256 (x=127, y=87)
;--------------------------------------------------

CIRCLE LD HL,127+87*256 ;(x=127, y=87)
LD D,1 ;r=50
LD C,D: LD B,0
CALL DOT
LD A,C: NEG: RET Z: LD C,A: CALL DOT
LD B,C: LD C,0
CALL DOT
LD A,B: NEG: LD B,A: CALL DOT
DEC D: RET Z
jr DLOOP
LOOP CALL DOT ;sector 1
LD A,B: NEG: LD B,A: CALL DOT ;sector 4
LD A,C: NEG: LD C,A: CALL DOT ;sector 5
LD A,B: NEG: LD B,A: CALL DOT ;sector 8
HLOOP
LD A,C: LD C,B: LD B,A: CALL DOT ;sector 3
LD A,C: NEG: LD C,A: CALL DOT ;sector 6
LD A,B: NEG: LD B,A: CALL DOT ;sector 7
LD A,C: NEG: LD C,A: CALL DOT ;sector 8
LD A,C: LD C,B: LD B,A
DLOOP
INC C
LD A,D: SUB C: LD D,A: JR NC,LOOP
DEC B
LD A,D: ADD A,B: LD D,A
LD A,C: CP B: JR C,LOOP
JP Z,HLOOP
RET

DOT PUSH HL: PUSH DE: PUSH BC
LD A,H: ADD A,B: LD B,A
LD A,L: ADD A,C: LD C,A
CALL #22e5
POP bc: POP DE: POP HL
RET

Sergey
07.10.2015, 07:22
Я протестировал его с фиксом, предложенным Destr, - запоминать координаты предыдущей точки и если текущие совпадают с ними, то не рисовать... Причина - некоторые (но не все) точки по одним координатам рисуются не подряд.

Ну я же уже объяснил, почему точки дублируются. :v2_dizzy_facepalm: Алогритм Destr`а, априори, не мог помочь. Контролируйте текущие x/y на нулевые значения.

Oleg N. Cher
07.10.2015, 22:24
Было бы хорошо нам иметь централизованное хранилище таких базовых вещей. Например, вот эта процедура (с правками Reobne конечно) вполне достойна быть включенной туда на правах минималистичной, хотя наверное и не самой идеальной с плане красивости отрисовки окружности. Ну можно и другую процедуру, которая побольше, но красивше рисует. Я просто не знаю такого хранилища, вместо него на просторах инета, на форумах и в прессе туча различных процедур, среди которых довольно много плохо закодированных. И всё это надо разгребать, тестировать, ругаться и т.д.

Но в ZXDev уже вошла. :) Reobne, огромное спасибо тебе.

GM BIT
15.10.2015, 12:39
Я что-то забросил сбор таких важностей

char
15.10.2015, 15:28
всё велосипеды чудите... :)
хотя бы
ld a,x:neg:ld x,a на xor a:sub x:ld x,a
поменяли...

char
23.10.2015, 00:57
вот, кстати, тогда - аж заэкранно рисующая процедура, из старинного DEJA VU журнала, с алгоритмом хитро вложенных друг в друга CALL'ов:
http://www.zxpress.ru/article.php?id=7876


;----------------------------------------;
_NULL EQU 0
;----------------------------------------;
ATTR_P EQU 23693 ;атрибуты экрана
;----------------------------------------;
;биты: 0 - over 0/1, 2 - inverse 0/1
; 4 - ink & paper 9 (прозрачные атр.)
P_FLAG EQU 23697
;----------------------------------------;

;----------------------------------------;
;Algorythm designed by SerzhSoft (c)1996
;рисование окружности
; HL=x, DE=y (-32768..+23767)
; A=радиус (0..255) ;при 0 - точка
CIRCLE
ld (X_CIRC),hl
ld (Y_CIRC),de
ld e,a
ld c,#00
ld b,c
ld d,c
srl a
LPCIR1 ex af,af'
LPCIR2 call PUT8PX
inc c
ex af,af'
sub c
jr nc,LPCIR1
dec e
add a,e
ex af,af'
ld a,e
cp c
jr nc,LPCIR2
ret
;
PUT8PX call PUT4PX
;
PUT4PX ld a,c
ld c,e
ld e,a
ld hl,_NULL
X_CIRC equ $-2
push hl
add hl,bc
call PUT2PX
pop hl
sbc hl,bc
;
PUT2PX inc h
dec h
ret nz
ld a,l
ld (X_NEW),a
ld hl,_NULL
Y_CIRC equ $-2
push hl
add hl,de
call PUT1PX
pop hl
sbc hl,de
;
PUT1PX inc h
dec h
ret nz
ld a,l
cp #C0
ret nc
push de
ld d,a
ld e,_NULL
X_NEW equ $-1
push bc
call PLOT
pop bc
pop de
ret
;----------------------------------------;

;----------------------------------------;
;выч. адреса и проверка состояния точки
POINT
LD B,#07
LD A,D
RRA
SCF
RRA
RRA
AND #5F
LD H,A
XOR E
AND B
XOR E
RRCA
RRCA
RRCA
LD L,A
LD A,D
XOR H
AND B
XOR H
LD H,A
LD A,E
AND B
LD B,A
LD A,#80
JR Z,GO_PNT
LP_PNT RRCA
DJNZ LP_PNT
GO_PNT LD C,A
AND (HL)
RET
;
POINTHL
PUSH HL
CALL POINT
POP HL
RET
;----------------------------------------;
;установка точки
PLOT
CALL POINT
LD A,(P_FLAG)
PUSH HL
LD HL,#A9A9 ;over 1, inv. 1
BIT 0,A
JR NZ,IF_PLT1
LD L,#B1 ;[or c] - over 0
IF_PLT1 BIT 2,A
JR NZ,IF_PLT2
LD H,#00 ;[nop] - inverse 1
IF_PLT2 LD (OVR_PLT),HL
POP HL
LD A,(HL)
OVR_PLT OR C
INV_PLT XOR C
;
TO_PLOT ;вход для пр-ры заливки и др.
LD (HL),A
LD A,(P_FLAG)
BIT 4,A
RET NZ
LD A,H
RRA
RRA
RRA
AND #03
OR #58
LD H,A
LD A,(ATTR_P)
LD (HL),A
RET
;----------------------------------------;


для over 1 добавляем:



...

PUT8PX call PUT4PX
ld a,c
cp e
ret z

...

call PUT2PX
pop hl
ld a,c
or a
ret z

...

call PUT1PX
pop hl
ld a,e
or a
ret z



и багфикс для 0 радиуса ( когда E сразу вываливается на 255 и пытается нарисовать к точке еще и окружность ), - заменить srl a:

or a
jr z,PUT4PX
rra