;----------------------------------------------------------------------- ; ; MODULE XCIRCLE ; ; This module was written by Matthew MacKenzie ; matm@eng.umd.edu ; ; Circles, full and empty. ; ; Compile with Tasm. ; C callable. ; ; ****** XLIB - Mode X graphics library **************** ; ****** **************** ; ; egg@dstos3.dsto.gov.au ; teg@bart.dsto.gov.au ;----------------------------------------------------------------------- include xlib.inc include xcircle.inc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; _x_circle ; ; Draw a circle. ; ; C near-callable as: ; int x_circle (WORD Left, WORD Top, WORD Diameter, ; WORD Color, WORD ScreenOffs); ; ; No clipping is performed. ; ; ax, bx, cx, and dx bite the dust, as Homer would say. ; we plot into eight arcs at once: ; 4 0 ; 6 \|/ 2 ; --*-- ; 7 /|\ 3 ; 5 1 ; ; 0, 1, 4, and 5 are considered x-major; the rest, y-major. ; ; The x-major plots grow out from the top and bottom of the circle, ; while the y-major plots start at the left and right edges. .data align 2 ColumnMask db 011h,022h,044h,088h .code public _x_circle align 2 _x_circle proc ARG Left:word, Top:word, Diameter:word, Color:word, ScreenOffs:word LOCAL offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error:word=LocalStk ; Tasm 1.0 does not allow the \ line continuation ;LOCAL offset0:word, offset1:word, offset2:word, offset3:word, \ ; offset4:word, offset5:word, offset6:word, offset7:word, \ ; mask0n1:word, mask2n3:word, mask4n5:word, mask6n7:word, \ ; shrunk_radius:word, diameter_even:word, error:word=LocalStk push bp mov bp, sp sub sp, LocalStk push si push di push ds ; find starting locations of plots 2, 3, 6, and 7 mov di, _ScrnLogicalByteWidth xor dx, dx mov ax, Diameter ; find vertical midpoint dec ax shr ax, 1 adc dx, 0 ; remember if it's rounded mov shrunk_radius, ax ; radius, rounded down for adding mov diameter_even, dx ; (diameter - 1) & 1, effectively add ax, Top mul di ; vertical midpoint in bytes add ax, ScreenOffs mov bx, Left mov cx, bx ; save for later mov si, bx shr si, 2 add si, ax mov offset6, si and bx, 3 ; column of left side mov bl, ColumnMask[bx] mov mask6n7, bx add cx, Diameter dec cx mov bx, cx shr cx, 2 add cx, ax mov offset2, cx and bx, 3 ; column of right side mov bl, ColumnMask[bx] mov mask2n3, bx cmp diameter_even, 1 jne @@MiddlePlotsOverlap add si, di add cx, di @@MiddlePlotsOverlap: mov offset7, si mov offset3, cx ; starting locations of 0, 1, 4, and 5 mov bx, Left add bx, shrunk_radius ; find horizontal midpoint mov ax, Top ; top in bytes mul di add ax, ScreenOffs mov si, ax mov ax, Diameter ; bottom in bytes dec ax mul di add ax, si mov di, bx ; horizontal midpoint in bytes shr di, 2 add si, di ; top midpoint in bytes mov offset4, si add di, ax ; bottom midpoint in bytes mov offset5, di and bx, 3 ; column of horizontal midpoint mov bl, ColumnMask[bx] mov mask4n5, bx cmp diameter_even, 1 jne @@TopAndBottomPlotsOverlap rol bl, 1 jnc @@TopAndBottomPlotsOverlap inc si inc di @@TopAndBottomPlotsOverlap: mov offset0, si mov offset1, di mov mask0n1, bx ; we've got our eight plots in their starting positions, so ; it's time to sort out the registers mov bx, _ScrnLogicalByteWidth mov dx, SCREEN_SEG mov ds, dx mov dx, SC_INDEX ; set VGA to accept column masks mov al, MAP_MASK out dx, al inc dx ; gun the engine... mov si, Diameter ; initial y is radius -- 2 #s per pixel inc si mov cx, si neg cx add cx, 2 mov error, cx ; error = -y + one pixel since we're a step ahead xor cx, cx ; initial x = 0 mov ah, byte ptr Color jmp @@CircleCalc ; let's actually put something on the screen! ; move the x-major plots horizontally and the y-major plots vertically @@NoAdvance: mov al, byte ptr mask0n1 out dx, al mov di, offset0 ; plot 0 mov [di], ah rol al, 1 ; advance 0 right mov byte ptr mask0n1, al adc di, 0 mov offset0, di mov di, offset1 mov [di], ah ; plot 1 ror al, 1 ; what was that bit again? adc di, 0 ; advance 1 right mov offset1, di mov al, byte ptr mask2n3 out dx, al mov di, offset2 mov [di], ah ; plot 2 sub di, bx ; advance 2 up mov offset2, di mov di, offset3 mov [di], ah ; plot 3 add di, bx ; advance 3 down mov offset3, di mov al, byte ptr mask4n5 out dx, al mov di, offset4 mov [di], ah ror al, 1 mov byte ptr mask4n5, al sbb di, 0 mov offset4, di mov di, offset5 mov [di], ah rol al, 1 sbb di, 0 mov offset5, di mov al, byte ptr mask6n7 out dx, al mov di, offset6 mov [di], ah sub di, bx mov offset6, di mov di, offset7 mov [di], ah add di, bx mov offset7, di jmp @@CircleCalc ; move all plots diagonally @@Advance: mov al, byte ptr mask0n1 out dx, al mov di, offset0 mov [di], ah ; plot 0 rol al, 1 ; advance 0 right and down mov byte ptr mask0n1, al adc di, bx mov offset0, di mov di, offset1 mov [di], ah ; plot 1 ror al, 1 ; what was that bit again? adc di, 0 ; advance 1 right and up sub di, bx mov offset1, di mov al, byte ptr mask2n3 out dx, al mov di, offset2 mov [di], ah ; plot 2 ror al, 1 ; advance 2 up and left mov byte ptr mask2n3, al sbb di, bx mov offset2, di mov di, offset3 mov [di], ah ; plot 3 rol al, 1 sbb di, 0 ; advance 3 down and left add di, bx mov offset3, di mov al, byte ptr mask4n5 out dx, al mov di, offset4 mov [di], ah ror al, 1 mov byte ptr mask4n5, al sbb di, 0 add di, bx mov offset4, di mov di, offset5 mov [di], ah rol al, 1 sbb di, bx mov offset5, di mov al, byte ptr mask6n7 out dx, al mov di, offset6 mov [di], ah rol al, 1 mov byte ptr mask6n7, al adc di, 0 sub di, bx mov offset6, di mov di, offset7 mov [di], ah ror al, 1 adc di, bx mov offset7, di ; do you realize the entire function has been set up for this little jot? ; keep in mind that radii values are 2 per pixel @@CircleCalc: add cx, 2 ; x += 1 mov di, error add di, cx ; error += (2 * x) + 1 inc di jl @@CircleNoError cmp cx, si ; x > y? ja @@FleeFlyFlowFum sub si, 2 ; y -= 1 sub di, si ; error -= (2 * y) mov error, di jmp @@Advance @@CircleNoError: mov error, di jmp @@NoAdvance @@FleeFlyFlowFum: pop ds pop di pop si mov sp,bp pop bp ret _x_circle endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; _x_filled_circle ; ; Draw a disc. ; ; C near-callable as: ; int x_filled_circle (WORD Left, WORD Top, WORD Diameter, ; WORD Color, WORD ScreenOffs); ; ; No clipping is performed. ; ; ax, bx, cx, dx, and es bite the dust, as Homer would say. ; DF is set to 0 (strings go forward). .data align 2 ; the only entries of these tables which are used are positions ; 1, 2, 4, and 8 LeftMaskTable db 0, 0ffh, 0eeh, 0, 0cch, 0, 0, 0, 088h RightMaskTable db 0, 011h, 033h, 0, 077h, 0, 0, 0, 0ffh .code public _x_filled_circle align 2 _x_filled_circle proc ARG Left:word, Top:word, Diameter:word, Color:word, ScreenOffs:word ; Tasm 1.0 does not allow the \ line continuation ;LOCAL offset0:word, offset1:word, offset2:word, offset3:word, \ ; offset4:word, offset5:word, offset6:word, offset7:word, \ ; mask0n1:word, mask2n3:word, mask4n5:word, mask6n7:word, \ ; shrunk_radius:word, diameter_even:word, error:word, \ ; jump_vector:word=LocalStk LOCAL offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error,jump_vector:word=LocalStk push bp mov bp, sp sub sp, LocalStk push si push di cld ; strings march forward ; this first part is identical to the other function -- ; the only differences, in fact, are in the drawing and moving around ; find starting locations of plots 2, 3, 6, and 7 mov di, _ScrnLogicalByteWidth xor dx, dx mov ax, Diameter ; find vertical midpoint dec ax shr ax, 1 adc dx, 0 ; remember if it's rounded mov shrunk_radius, ax ; radius, rounded down for adding mov diameter_even, dx ; (diameter - 1) & 1, effectively add ax, Top mul di ; vertical midpoint in bytes add ax, ScreenOffs mov bx, Left mov cx, bx ; save for later mov si, bx shr si, 2 add si, ax mov offset6, si and bx, 3 ; column of left side mov bl, ColumnMask[bx] mov mask6n7, bx add cx, Diameter dec cx mov bx, cx shr cx, 2 add cx, ax mov offset2, cx and bx, 3 ; column of right side mov bl, ColumnMask[bx] mov mask2n3, bx cmp diameter_even, 1 jne @@MiddlePlotsOverlap add si, di add cx, di @@MiddlePlotsOverlap: mov offset7, si mov offset3, cx ; starting locations of 0, 1, 4, and 5 mov bx, Left add bx, shrunk_radius ; find horizontal midpoint mov ax, Top ; top in bytes mul di add ax, ScreenOffs mov si, ax mov ax, Diameter ; bottom in bytes dec ax mul di add ax, si mov di, bx ; horizontal midpoint in bytes shr di, 2 add si, di ; top midpoint in bytes mov offset4, si add di, ax ; bottom midpoint in bytes mov offset5, di and bx, 3 ; column of horizontal midpoint mov bl, ColumnMask[bx] mov mask4n5, bx cmp diameter_even, 1 jne @@TopAndBottomPlotsOverlap rol bl, 1 jnc @@TopAndBottomPlotsOverlap inc si inc di @@TopAndBottomPlotsOverlap: mov offset0, si mov offset1, di mov mask0n1, bx ; we've got our eight plots in their starting positions, so ; it's time to sort out the registers mov bx, _ScrnLogicalByteWidth mov dx, SCREEN_SEG mov es, dx mov dx, SC_INDEX ; set VGA to accept column masks mov al, MAP_MASK out dx, al inc dx ; gun the engine... mov si, Diameter ; initial y is radius -- 2 #s per pixel inc si mov cx, si neg cx add cx, 2 mov error, cx ; error = -y + one pixel since we're a step ahead xor cx, cx ; initial x = 0 mov ah, byte ptr Color jmp @@FilledCircleCalc ; let's actually put something on the screen! ; plotting is completely different from in the other function (naturally) @@PlotLines: push cx ; we'll need cx for string stores ; draw x-major horz. lines, from plot 4 to plot 0 and from plot 5 to plot 1 mov di, mask0n1 and di, 0000fh ; we only want the lower nybble for the mask table mov al, RightMaskTable[di] mov di, offset0 ; left and right offsets the same? cmp di, offset4 jne @@PlotXMajorNontrivial ; try and say this one 10 times fast! mov di, mask4n5 and di, 0000fh and al, LeftMaskTable[di] ; intersection of left & right masks out dx, al ; set mask mov di, offset4 mov es:[di], ah mov di, offset5 mov es:[di], ah jmp @@PlotYMajor @@PlotXMajorNontrivial: out dx, al ; draw right edge mov es:[di], ah mov di, offset1 mov es:[di], ah mov di, mask4n5 ; draw left edge and di, 0000fh mov al, LeftMaskTable[di] out dx, al mov di, offset4 mov es:[di], ah mov di, offset5 mov es:[di], ah mov al, 0ffh ; set mask for middle chunks out dx, al mov al, ah ; ready to store two pixels at a time inc di ; move string start past left edge mov cx, offset1 ; store line from plot 5 to plot 1, exclusive sub cx, di ; width of section in bytes push cx shr cx, 1 ; draw midsection eight pixels at a time rep stosw adc cx, 0 ; draw last four pixels, if such there are rep stosb mov di, offset4 ; draw line from plot 4 to plot 0 inc di ; move past left edge pop cx shr cx, 1 rep stosw adc cx, 0 rep stosb @@PlotYMajor: ; draw y-major horz. lines, from plot 6 to plot 2 and from plot 7 to plot 3 mov di, mask2n3 and di, 0000fh ; we only want the lower nybble for the mask table mov al, RightMaskTable[di] mov di, offset2 ; left and right offsets the same? cmp di, offset6 jne @@PlotYMajorNontrivial ; try and say this one 10 times fast! mov di, mask6n7 and di, 0000fh and al, LeftMaskTable[di] ; intersection of left & right masks out dx, al ; set mask mov di, offset6 mov es:[di], ah mov di, offset7 mov es:[di], ah jmp @@ClimaxOfPlot @@PlotYMajorNontrivial: out dx, al ; draw right edge mov es:[di], ah mov di, offset3 mov es:[di], ah mov di, mask6n7 ; draw left edge and di, 0000fh mov al, LeftMaskTable[di] out dx, al mov di, offset6 mov es:[di], ah mov di, offset7 mov es:[di], ah mov al, 0ffh ; set mask for middle chunks out dx, al mov al, ah ; ready to store two pixels at a time inc di ; move string start past left edge mov cx, offset3 ; draw line from plot 7 to plot 3, exclusive sub cx, di ; width of section in bytes push cx shr cx, 1 ; store midsection rep stosw adc cx, 0 rep stosb mov di, offset6 ; draw line from plot 6 to plot 2 inc di ; move past left edge pop cx shr cx, 1 rep stosw adc cx, 0 rep stosb @@ClimaxOfPlot: pop cx jmp [jump_vector] ; either @@Advance or @@NoAdvance ; unlike their counterparts in the other function, these do not draw -- ; they only move the eight pointers ; move the x-major plots horizontally and the y-major plots vertically @@NoAdvance: mov al, byte ptr mask0n1 ; advance left x-major plots mov di, offset0 rol al, 1 ; advance 0 right mov byte ptr mask0n1, al adc di, 0 mov offset0, di mov di, offset1 ror al, 1 ; what was that bit again? adc di, 0 ; advance 1 right mov offset1, di mov al, byte ptr mask4n5 ; advance left x-major plots mov di, offset4 ror al, 1 mov byte ptr mask4n5, al sbb di, 0 mov offset4, di mov di, offset5 rol al, 1 sbb di, 0 mov offset5, di mov al, byte ptr mask2n3 mov di, offset2 sub di, bx ; advance 2 up mov offset2, di mov di, offset3 add di, bx ; advance 3 down mov offset3, di mov al, byte ptr mask6n7 mov di, offset6 sub di, bx mov offset6, di mov di, offset7 add di, bx mov offset7, di jmp @@FilledCircleCalc ; move all plots diagonally @@Advance: mov al, byte ptr mask0n1 mov di, offset0 rol al, 1 ; advance 0 right and down mov byte ptr mask0n1, al adc di, bx mov offset0, di mov di, offset1 ror al, 1 ; what was that bit again? adc di, 0 ; advance 1 right and up sub di, bx mov offset1, di mov al, byte ptr mask2n3 mov di, offset2 ror al, 1 ; advance 2 up and left mov byte ptr mask2n3, al sbb di, bx mov offset2, di mov di, offset3 rol al, 1 sbb di, 0 ; advance 3 down and left add di, bx mov offset3, di mov al, byte ptr mask4n5 mov di, offset4 ror al, 1 mov byte ptr mask4n5, al sbb di, 0 add di, bx mov offset4, di mov di, offset5 rol al, 1 sbb di, bx mov offset5, di mov al, byte ptr mask6n7 mov di, offset6 rol al, 1 mov byte ptr mask6n7, al adc di, 0 sub di, bx mov offset6, di mov di, offset7 ror al, 1 adc di, bx mov offset7, di ; do you realize the entire function has been set up around this little jot? ; keep in mind that radii values are 2 per pixel @@FilledCircleCalc: add cx, 2 ; x += 1 mov di, error add di, cx ; error += (2 * x) + 1 inc di jl @@FilledCircleNoError cmp cx, si ; x > y? ja @@FleeFlyFlowFum sub si, 2 ; y -= 1 sub di, si ; error -= (2 * y) mov error, di mov jump_vector, offset @@Advance jmp @@PlotLines @@FilledCircleNoError: mov error, di mov jump_vector, offset @@NoAdvance jmp @@PlotLines @@FleeFlyFlowFum: pop di pop si mov sp,bp pop bp ret _x_filled_circle endp end