81 variations of the rounded rectangle

If we apply outward curving, inward curving, and no curving at all, individually to each of the 4 corners of the rectangle, we get next 81 variations:

The code implements next BASIC command:

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


BOX draws the rectangle between the opposite corners at (X1%, Y1%) and (X2%, Y2%). The first byte of the 32-bit value in Radii% defines the first quadrant corner, the second byte of Radii% defines the second quadrant corner, and so on. These bytes, independent of each other, express a percentage of the half of the smallest dimension of the rectangle. A positive value rounds outwards (convex), a negative value rounds inwards (concave), a zero doesn't round at all.
The arcs are drawn via an 8-point-symmetrical Bresenham code. This means that for each 90° arc, points are drawn simultaneously moving towards the bisector.

If the intent were to draw the whole rounded rectangle using some dotted linestyle, then it would be very desirable to draw all of these arcs entirely in an anti-clockwise fashion only. How can this be done, using either the Bresenham algorithm or a similar one ?
Also, can the present code be optimized any further (codesize and/or execution speed) ?

; 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
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
mov     bp, sp          ; Args start at BP+36
mov     ax, 0A000h
mov     es, ax

; 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
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
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
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
.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
.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)
jmp     .e
.d:     sub     cx, ax
dec     ax              ; Y=Y-1
.e:     shl     cx, 2
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
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