81 вариант прямоугольника с закругленными углами

Если мы применяем изгибание наружу, изгибание внутрь и совсем не изгибаемся, индивидуально к каждому из 4-х углов прямоугольника получаем 81 вариант:

Закругленные прямоугольники

Код реализует следующую команду BASIC:

BOX X1%, Y1%, X2%, Y2% RADII Radii%

BOX рисует прямоугольник между противоположными углами в точках (X1%, Y1%) и (X2%, Y2%). Первый байт 32-битного значения в Радиусы% определяет угол первого квадранта, второй байт Радиусы% определяет угол второго квадранта и так далее. Эти байты, независимые друг от друга, выражают процент от половины наименьшего размера прямоугольника. Положительное значение округляется наружу (выпукло), отрицательное значение округляется внутрь (вогнутое), нулевое значение не округляется вообще.
Дуги нарисованы с помощью 8-точечного симметричного кода Брезенхема. Это означает, что для каждой дуги 90 ° одновременно рисуются точки, движущиеся к биссектрисе.

Если бы цель заключалась в том, чтобы нарисовать весь закругленный прямоугольник с использованием некоторого пунктирного стиля линий, тогда было бы очень желательно нарисовать все эти дуги полностью только против часовой стрелки. Как это можно сделать, используя алгоритм Брезенхема или аналогичный?
Кроме того, можно ли еще оптимизировать существующий код (размер кода и / или скорость выполнения)?

; Rounded Box (c) 2021 Sep Roland
; Assemble with FASM

        ORG     256

        mov     ax, 0013h       ; BIOS.SetVideoMode 320x200
        int     10h

        mov     [Color], 4      ; Red
        push    dword 64643232h ; Q4=100% Q3=100% Q2=50% Q1=50%
        push    89 189 10 130
        call    Box             ; 'BOX 130,10,189,89 RADII Bytes(50,50,100,100)'

        mov     [Color], 14     ; Yellow
        push    dword 00006464h ; Q4=0% Q3=0% Q2=100% Q1=100%
        push    189 189 110 130
        call    Box             ; 'BOX 130,110,189,189 RADII Bytes(100,100,0,0)'

        mov     [Color], 1      ; Blue
        push    dword 9C00329Ch ; Q4=-100% Q3=0% Q2=50% Q1=-100%
        push    129 149 70 10
        call    Box             ; 'BOX 10,70,149,129 RADII Bytes(-100,50,0,-100)'

        mov     [Color], 2      ; Green
        push    dword 009C9C32h ; Q4=0% Q3=-100% Q2=-100% Q1=50%
        push    129 309 70 170
        call    Box             ; 'BOX 170,70,309,129 RADII Bytes(50,-100,-100,0)'

        mov     ah, 00h         ; BIOS.WaitKey
        int     16h             ; -> AX
        mov     ax, 0003h       ; BIOS.SetVideoMode 80x25
        int     10h
        mov     ax, 4C00h       ; DOS.Terminate
        int     21h
; -----------------------------
; Plots single pixel on the 256-color screen
; IN (ax,bx,es) OUT ()
PT:     push    ax di           ; AX=Y BX=X
        mov     di, ax
        shl     di, 6
        xchg    al, ah
        add     di, ax
        mov     al, [Color]
        mov     [es:di+bx], al
        pop     di ax
        ret
; -----------------------------
; Draws rectangle with optional, individually outward or inward, curving corners
; IN () OUT ()
Box:    push    es
        pushad
        mov     bp, sp          ; Args start at BP+36
        mov     ax, 0A000h
        mov     es, ax
        mov     ecx, [bp+36+8]  ; Radii

; SI = Min(Width,Height)-1
        mov     si, [bp+36+6]   ; Y2
        sub     si, [bp+36+2]   ; Y1 -> SI is DeltaY
        mov     ax, [bp+36+4]   ; X2
        sub     ax, [bp+36+0]   ; X1 -> AX is DeltaX
        cmp     si, ax
        jbe     .Q1
        mov     si, ax

;   Q4    Q3    Q2    Q1
; |     |     |     | <-- Convex --> <-- Concave ->           |
; |  "  |  "  |  "  |  Xc   Yc  Arc   Xc   Yc  Arc   R    %   |
; |     |     |     | ---- ---- ---- ---- ---- ---- ---- ---- |
; ^                                                           ^
; SP <-------------------- 4 * 8 words ---------------------> BP

.Q1:    push    cx
        call    .Radius         ; -> AX ECX (BX DX)
        push    ax
        mov     dx, [bp+36+2]   ; Y1
        mov     bx, [bp+36+4]   ; X2
        push    .Q3Arc dx bx
        add     dx, ax
        sub     bx, ax
        push    .Q1Arc dx bx

.Q2:    push    cx
        call    .Radius         ; -> AX ECX (BX DX)
        push    ax
        mov     dx, [bp+36+2]   ; Y1
        mov     bx, [bp+36+0]   ; X1
        push    .Q4Arc dx bx
        add     dx, ax
        add     bx, ax
        push    .Q2Arc dx bx

.Q3:    push    cx
        call    .Radius         ; -> AX ECX (BX DX)
        push    ax
        mov     dx, [bp+36+6]   ; Y2
        mov     bx, [bp+36+0]   ; X1
        push    .Q1Arc dx bx
        sub     dx, ax
        add     bx, ax
        push    .Q3Arc dx bx

.Q4:    push    cx
        call    .Radius         ; -> AX ECX (BX DX)
        push    ax
        mov     dx, [bp+36+6]   ; Y2
        mov     bx, [bp+36+4]   ; X2
        push    .Q2Arc dx bx
        sub     dx, ax
        sub     bx, ax
        push    .Q4Arc dx bx

        mov     si, sp          ; DS=SS
        add     si, 4*16
.Arcs:  sub     si, 16
        mov     ax, [si+12]     ; Current radius
        test    ax, ax          ; No curving if radius=0
        jz      .f
        push    si              ; (1)
        xor     bx, bx          ; Start at (0,R)
        cmp     [si+14], bl     ; BL=0
        jg      .a              ; Convex
        add     si, 6           ; Concave
.a:     mov     di, 3           ; Decision variable D=3-2*R
        sub     di, ax
        sub     di, ax
        jmp     .c              ; Skip all tops (belong to sides)
.b:     push    ax bx           ; (2)
        call    word [si+4]     ; Plot arc
        pop     bx ax           ; (2)
.c:     mov     cx, bx
        test    di, di          ; If D<0  then D=D+6+4*X
        jns     .d              ; If D>=0 then D=D+10+4*(X-Y)
        add     di, 6           ;              Y=Y-1
        jmp     .e
.d:     sub     cx, ax
        add     di, 10
        dec     ax              ; Y=Y-1
.e:     shl     cx, 2
        add     di, cx
        inc     bx              ; X=X+1
        cmp     bx, ax
        jbe     .b              ; While X<=Y
        pop     si              ; (1)
.f:     cmp     si, sp
        jne     .Arcs

.North: mov     ax, [si+32+8]   ; Y1, Going from East to West
        mov     bx, [si+48]     ; Q1Xc
@@:     call    PT
        dec     bx
        cmp     bx, [si+32]     ; Q2Xc
        jge     @b

.West:  mov     bx, [si+16+6]   ; X1, going from North to South
        mov     ax, [si+32+2]   ; Q2Yc
@@:     call    PT
        inc     ax
        cmp     ax, [si+16+2]   ; Q3Yc
        jle     @b

.South: mov     ax, [si+8]      ; Y2, going from West to East
        mov     bx, [si+16]     ; Q3Xc
@@:     call    PT
        inc     bx
        cmp     bx, [si]        ; Q4Xc
        jle     @b

.East:  mov     bx, [si+6]      ; X2, going from South to North
        mov     ax, [si+2]      ; Q4Yc
@@:     call    PT
        dec     ax
        cmp     ax, [si+48+2]   ; Q1Yc
        jge     @b

        mov     sp, bp
        popad
        pop     es
        ret     12
; - - - - - - - - - - - - - - -
; IN (ecx,si) OUT (ax,ecx) MOD (bx,dx)
.Radius:movsx   ax, cl          ; Inputted percentage [-128,+127]
; AX = Min(Abs(Percentage),100)
        test    ax, ax
        jns     @f
        neg     ax
@@:     cmp     ax, 100
        jna     @f
        mov     ax, 100
; AX = (SI/2)*AX/100
@@:     mul     si              ; AX is percentage [0,100]
        mov     bx, 200
        div     bx              ; -> AX is radius 0+
; Prepare for the next quadrant's percentage
        shr     ecx, 8
        ret
; - - - - - - - - - - - - - - -
.Q1Arc: neg     ax
        jmp     .PT___
; - - - - - - - - - - - - - - -
.Q2Arc: neg     bx
        neg     ax
        jmp     .PT__
; - - - - - - - - - - - - - - -
.Q3Arc: neg     bx
.PT___: call    .PT
        neg     bx
        neg     ax
        jmp     .PT_
; - - - - - - - - - - - - - - -
.Q4Arc: xchg    ax, bx
.PT__:  call    .PT
.PT_:   xchg    ax, bx
; ---   ---   ---   ---   ---
.PT:    add     bx, [si]        ; X plus current Xc
        add     ax, [si+2]      ; Y plus current Yc
        call    PT
        sub     bx, [si]        ; Restore X
        sub     ax, [si+2]      ; Restore Y
        ret
; ------------------------------
Color   rb      1

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *