1
\$\begingroup\$

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:

Rounded rectangles

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
        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
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.