Столкнулся с такой проблемой существующих процедур рисования окружности, которые можно, в частности, найти здесь на форуме. Например, алгоритм из "Библии демомейкера" в OVER 1 рисует такую окружность:
Вид для печати
Столкнулся с такой проблемой существующих процедур рисования окружности, которые можно, в частности, найти здесь на форуме. Например, алгоритм из "Библии демомейкера" в OVER 1 рисует такую окружность:
То есть некоторые точки рисуются по два раза. И даже если вообще никто не рисует окружности в режиме OVER 1, то всё равно это - потеря производительности.
Стандартная ПЗУ'шная процедура такой проблемы не имеет.
Хотелось бы найти быструю и корректную в этом смысле процедуру. Что посоветуете?
Есть у меня ещё одна процедура (не помню откуда брал), интересная тем, что радиус можно задавать двухбайтовым числом. И можно рисовать за пределами экрана.
Скрытый текст
Код: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;
}
[свернуть]
Но у неё та же проблема:
shurik-ua, спасибо конечно. Но уточню: мне нужна не теория и алгоритм на псевдобейсике, а нормальный отлаженный код на ассемблере Z80. Или совет как пофиксить упомянутые выше процедуры.
Вторую хотелось бы отладить особенно, потому что она редкостная - большинство процедур, которые я здесь встречал, имеют однобайтовые аргументы.
Возможно рисует по две точки как раз из за упрощения/ускорения рисования, просто пожертвовали лишними проверками или точностью алгоритма
Мы хотим получить круто оптимизированный код на ассемблере, чтобы он прямо пиксель в пиксель повторял результат рисования бейсиковского круга? Или можно немножко переставить пикселки в углах, главное чтобы два раза в одном месте не рисовалось, и смотрелось правильно?
Вход определим. X,Y,Z- целые? байт? слово(2 байта) со знаком?
Результат:
На весь экран? (256x192)
Круг частично выходит за экран?
Атрибуты красим? (инк, папер, яркость мигание)
Как опции можно сделать круги с заливкой. Нужно?
В этой процедуре последнюю точку не печатать (если уже была).
Например так (новая подпрограмма печати точки)
Код: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
Фикс Destr'а рабочий и, в принципе, меня устраивает. Благодарю!
Думаю, можно.
Сейчас у меня просто стоит задача получить хоть какую-то окружность в OVER 1. Но в общем-то:
1. Для библиотеки Basic (ZXDev) нужна процедура окружности. CIRCLEROM там уже есть. CIRCLE задумана как то же самое, но быстрый вариант (все параметры - беззнаковые байты) и не позволяет рисовать за пределами экрана. CIRCLEW - то же самое, но все параметры - слова со знаком. Такой процедуры я не нашёл, поэтому пока удовольствовался процедурой, где координаты - байты без знака, а радиус - слово со знаком. Она умеет рисовать за пределами экрана не всю окружность, а только её часть.
Можно поспорить с тем, нужна ли CIRCLEW непосредственно в библиотеке Basic, но уже пускай будет - по аналогии с RND (результат - байт) и RNDW (результат - слово).
2. Для библиотеки Gfx, которую я недавно начал формировать, пригодились бы и другие варианты окружности, в т.ч. и залитой. Так что буду благодарен.
Не могу сказать, сколько раз рисуются точки, - это, вообще, странно слышать, что одна точка несколько раз рисуется. Зачем, также, этот кривой ПЗУшный алгоритм? - разве он не через 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;
}