1 ;-----------------------------------------------------------------------
\r
5 ; This module was written by Matthew MacKenzie
\r
8 ; Circles, full and empty.
\r
10 ; Compile with Tasm.
\r
13 ; ****** XLIB - Mode X graphics library ****************
\r
14 ; ****** ****************
\r
16 ; egg@dstos3.dsto.gov.au
\r
17 ; teg@bart.dsto.gov.au
\r
18 ;-----------------------------------------------------------------------
\r
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
28 ; C near-callable as:
\r
29 ; int x_circle (WORD Left, WORD Top, WORD Diameter,
\r
30 ; WORD Color, WORD ScreenOffs);
\r
32 ; No clipping is performed.
\r
34 ; ax, bx, cx, and dx bite the dust, as Homer would say.
\r
36 ; we plot into eight arcs at once:
\r
43 ; 0, 1, 4, and 5 are considered x-major; the rest, y-major.
\r
45 ; The x-major plots grow out from the top and bottom of the circle,
\r
46 ; while the y-major plots start at the left and right edges.
\r
52 ColumnMask db 011h,022h,044h,088h
\r
59 ARG Left:word, Top:word, Diameter:word, Color:word, ScreenOffs:word
\r
60 LOCAL offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error:word=LocalStk
\r
61 ; Tasm 1.0 does not allow the \ line continuation
\r
62 ;LOCAL offset0:word, offset1:word, offset2:word, offset3:word, \
\r
63 ; offset4:word, offset5:word, offset6:word, offset7:word, \
\r
64 ; mask0n1:word, mask2n3:word, mask4n5:word, mask6n7:word, \
\r
65 ; shrunk_radius:word, diameter_even:word, error:word=LocalStk
\r
74 ; find starting locations of plots 2, 3, 6, and 7
\r
75 mov di, _ScrnLogicalByteWidth
\r
78 mov ax, Diameter ; find vertical midpoint
\r
81 adc dx, 0 ; remember if it's rounded
\r
82 mov shrunk_radius, ax ; radius, rounded down for adding
\r
83 mov diameter_even, dx ; (diameter - 1) & 1, effectively
\r
85 mul di ; vertical midpoint in bytes
\r
89 mov cx, bx ; save for later
\r
94 and bx, 3 ; column of left side
\r
95 mov bl, ColumnMask[bx]
\r
104 and bx, 3 ; column of right side
\r
105 mov bl, ColumnMask[bx]
\r
108 cmp diameter_even, 1
\r
109 jne @@MiddlePlotsOverlap
\r
112 @@MiddlePlotsOverlap:
\r
116 ; starting locations of 0, 1, 4, and 5
\r
118 add bx, shrunk_radius ; find horizontal midpoint
\r
120 mov ax, Top ; top in bytes
\r
125 mov ax, Diameter ; bottom in bytes
\r
130 mov di, bx ; horizontal midpoint in bytes
\r
132 add si, di ; top midpoint in bytes
\r
134 add di, ax ; bottom midpoint in bytes
\r
136 and bx, 3 ; column of horizontal midpoint
\r
137 mov bl, ColumnMask[bx]
\r
140 cmp diameter_even, 1
\r
141 jne @@TopAndBottomPlotsOverlap
\r
143 jnc @@TopAndBottomPlotsOverlap
\r
146 @@TopAndBottomPlotsOverlap:
\r
151 ; we've got our eight plots in their starting positions, so
\r
152 ; it's time to sort out the registers
\r
153 mov bx, _ScrnLogicalByteWidth
\r
158 mov dx, SC_INDEX ; set VGA to accept column masks
\r
161 inc dx ; gun the engine...
\r
163 mov si, Diameter ; initial y is radius -- 2 #s per pixel
\r
169 mov error, cx ; error = -y + one pixel since we're a step ahead
\r
171 xor cx, cx ; initial x = 0
\r
172 mov ah, byte ptr Color
\r
173 jmp @@CircleCalc ; let's actually put something on the screen!
\r
175 ; move the x-major plots horizontally and the y-major plots vertically
\r
177 mov al, byte ptr mask0n1
\r
179 mov di, offset0 ; plot 0
\r
181 rol al, 1 ; advance 0 right
\r
182 mov byte ptr mask0n1, al
\r
186 mov [di], ah ; plot 1
\r
187 ror al, 1 ; what was that bit again?
\r
188 adc di, 0 ; advance 1 right
\r
191 mov al, byte ptr mask2n3
\r
194 mov [di], ah ; plot 2
\r
195 sub di, bx ; advance 2 up
\r
198 mov [di], ah ; plot 3
\r
199 add di, bx ; advance 3 down
\r
202 mov al, byte ptr mask4n5
\r
207 mov byte ptr mask4n5, al
\r
216 mov al, byte ptr mask6n7
\r
229 ; move all plots diagonally
\r
231 mov al, byte ptr mask0n1
\r
234 mov [di], ah ; plot 0
\r
235 rol al, 1 ; advance 0 right and down
\r
236 mov byte ptr mask0n1, al
\r
240 mov [di], ah ; plot 1
\r
241 ror al, 1 ; what was that bit again?
\r
242 adc di, 0 ; advance 1 right and up
\r
246 mov al, byte ptr mask2n3
\r
249 mov [di], ah ; plot 2
\r
250 ror al, 1 ; advance 2 up and left
\r
251 mov byte ptr mask2n3, al
\r
255 mov [di], ah ; plot 3
\r
257 sbb di, 0 ; advance 3 down and left
\r
261 mov al, byte ptr mask4n5
\r
266 mov byte ptr mask4n5, al
\r
276 mov al, byte ptr mask6n7
\r
281 mov byte ptr mask6n7, al
\r
291 ; do you realize the entire function has been set up for this little jot?
\r
292 ; keep in mind that radii values are 2 per pixel
\r
296 add di, cx ; error += (2 * x) + 1
\r
299 cmp cx, si ; x > y?
\r
300 ja @@FleeFlyFlowFum
\r
302 sub di, si ; error -= (2 * y)
\r
321 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
326 ; C near-callable as:
\r
327 ; int x_filled_circle (WORD Left, WORD Top, WORD Diameter,
\r
328 ; WORD Color, WORD ScreenOffs);
\r
330 ; No clipping is performed.
\r
332 ; ax, bx, cx, dx, and es bite the dust, as Homer would say.
\r
333 ; DF is set to 0 (strings go forward).
\r
339 ; the only entries of these tables which are used are positions
\r
341 LeftMaskTable db 0, 0ffh, 0eeh, 0, 0cch, 0, 0, 0, 088h
\r
342 RightMaskTable db 0, 011h, 033h, 0, 077h, 0, 0, 0, 0ffh
\r
346 public _x_filled_circle
\r
348 _x_filled_circle proc
\r
349 ARG Left:word, Top:word, Diameter:word, Color:word, ScreenOffs:word
\r
350 ; Tasm 1.0 does not allow the \ line continuation
\r
351 ;LOCAL offset0:word, offset1:word, offset2:word, offset3:word, \
\r
352 ; offset4:word, offset5:word, offset6:word, offset7:word, \
\r
353 ; mask0n1:word, mask2n3:word, mask4n5:word, mask6n7:word, \
\r
354 ; shrunk_radius:word, diameter_even:word, error:word, \
\r
355 ; jump_vector:word=LocalStk
\r
356 LOCAL offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error,jump_vector:word=LocalStk
\r
364 cld ; strings march forward
\r
366 ; this first part is identical to the other function --
\r
367 ; the only differences, in fact, are in the drawing and moving around
\r
369 ; find starting locations of plots 2, 3, 6, and 7
\r
370 mov di, _ScrnLogicalByteWidth
\r
373 mov ax, Diameter ; find vertical midpoint
\r
376 adc dx, 0 ; remember if it's rounded
\r
377 mov shrunk_radius, ax ; radius, rounded down for adding
\r
378 mov diameter_even, dx ; (diameter - 1) & 1, effectively
\r
380 mul di ; vertical midpoint in bytes
\r
384 mov cx, bx ; save for later
\r
389 and bx, 3 ; column of left side
\r
390 mov bl, ColumnMask[bx]
\r
399 and bx, 3 ; column of right side
\r
400 mov bl, ColumnMask[bx]
\r
403 cmp diameter_even, 1
\r
404 jne @@MiddlePlotsOverlap
\r
407 @@MiddlePlotsOverlap:
\r
411 ; starting locations of 0, 1, 4, and 5
\r
413 add bx, shrunk_radius ; find horizontal midpoint
\r
415 mov ax, Top ; top in bytes
\r
420 mov ax, Diameter ; bottom in bytes
\r
425 mov di, bx ; horizontal midpoint in bytes
\r
427 add si, di ; top midpoint in bytes
\r
429 add di, ax ; bottom midpoint in bytes
\r
431 and bx, 3 ; column of horizontal midpoint
\r
432 mov bl, ColumnMask[bx]
\r
435 cmp diameter_even, 1
\r
436 jne @@TopAndBottomPlotsOverlap
\r
438 jnc @@TopAndBottomPlotsOverlap
\r
441 @@TopAndBottomPlotsOverlap:
\r
446 ; we've got our eight plots in their starting positions, so
\r
447 ; it's time to sort out the registers
\r
448 mov bx, _ScrnLogicalByteWidth
\r
453 mov dx, SC_INDEX ; set VGA to accept column masks
\r
456 inc dx ; gun the engine...
\r
458 mov si, Diameter ; initial y is radius -- 2 #s per pixel
\r
464 mov error, cx ; error = -y + one pixel since we're a step ahead
\r
466 xor cx, cx ; initial x = 0
\r
467 mov ah, byte ptr Color
\r
468 jmp @@FilledCircleCalc ; let's actually put something on the screen!
\r
471 ; plotting is completely different from in the other function (naturally)
\r
473 push cx ; we'll need cx for string stores
\r
475 ; draw x-major horz. lines, from plot 4 to plot 0 and from plot 5 to plot 1
\r
477 and di, 0000fh ; we only want the lower nybble for the mask table
\r
478 mov al, RightMaskTable[di]
\r
479 mov di, offset0 ; left and right offsets the same?
\r
481 jne @@PlotXMajorNontrivial ; try and say this one 10 times fast!
\r
484 and al, LeftMaskTable[di] ; intersection of left & right masks
\r
485 out dx, al ; set mask
\r
491 @@PlotXMajorNontrivial:
\r
492 out dx, al ; draw right edge
\r
497 mov di, mask4n5 ; draw left edge
\r
499 mov al, LeftMaskTable[di]
\r
506 mov al, 0ffh ; set mask for middle chunks
\r
508 mov al, ah ; ready to store two pixels at a time
\r
509 inc di ; move string start past left edge
\r
510 mov cx, offset1 ; store line from plot 5 to plot 1, exclusive
\r
511 sub cx, di ; width of section in bytes
\r
513 shr cx, 1 ; draw midsection eight pixels at a time
\r
515 adc cx, 0 ; draw last four pixels, if such there are
\r
518 mov di, offset4 ; draw line from plot 4 to plot 0
\r
519 inc di ; move past left edge
\r
527 ; draw y-major horz. lines, from plot 6 to plot 2 and from plot 7 to plot 3
\r
529 and di, 0000fh ; we only want the lower nybble for the mask table
\r
530 mov al, RightMaskTable[di]
\r
531 mov di, offset2 ; left and right offsets the same?
\r
533 jne @@PlotYMajorNontrivial ; try and say this one 10 times fast!
\r
536 and al, LeftMaskTable[di] ; intersection of left & right masks
\r
537 out dx, al ; set mask
\r
543 @@PlotYMajorNontrivial:
\r
544 out dx, al ; draw right edge
\r
549 mov di, mask6n7 ; draw left edge
\r
551 mov al, LeftMaskTable[di]
\r
558 mov al, 0ffh ; set mask for middle chunks
\r
560 mov al, ah ; ready to store two pixels at a time
\r
562 inc di ; move string start past left edge
\r
563 mov cx, offset3 ; draw line from plot 7 to plot 3, exclusive
\r
564 sub cx, di ; width of section in bytes
\r
566 shr cx, 1 ; store midsection
\r
571 mov di, offset6 ; draw line from plot 6 to plot 2
\r
572 inc di ; move past left edge
\r
581 jmp [jump_vector] ; either @@Advance or @@NoAdvance
\r
584 ; unlike their counterparts in the other function, these do not draw --
\r
585 ; they only move the eight pointers
\r
587 ; move the x-major plots horizontally and the y-major plots vertically
\r
589 mov al, byte ptr mask0n1 ; advance left x-major plots
\r
591 rol al, 1 ; advance 0 right
\r
592 mov byte ptr mask0n1, al
\r
596 ror al, 1 ; what was that bit again?
\r
597 adc di, 0 ; advance 1 right
\r
600 mov al, byte ptr mask4n5 ; advance left x-major plots
\r
603 mov byte ptr mask4n5, al
\r
611 mov al, byte ptr mask2n3
\r
613 sub di, bx ; advance 2 up
\r
616 add di, bx ; advance 3 down
\r
619 mov al, byte ptr mask6n7
\r
627 jmp @@FilledCircleCalc
\r
629 ; move all plots diagonally
\r
631 mov al, byte ptr mask0n1
\r
633 rol al, 1 ; advance 0 right and down
\r
634 mov byte ptr mask0n1, al
\r
638 ror al, 1 ; what was that bit again?
\r
639 adc di, 0 ; advance 1 right and up
\r
643 mov al, byte ptr mask2n3
\r
645 ror al, 1 ; advance 2 up and left
\r
646 mov byte ptr mask2n3, al
\r
651 sbb di, 0 ; advance 3 down and left
\r
655 mov al, byte ptr mask4n5
\r
658 mov byte ptr mask4n5, al
\r
667 mov al, byte ptr mask6n7
\r
670 mov byte ptr mask6n7, al
\r
679 ; do you realize the entire function has been set up around this little jot?
\r
680 ; keep in mind that radii values are 2 per pixel
\r
681 @@FilledCircleCalc:
\r
684 add di, cx ; error += (2 * x) + 1
\r
686 jl @@FilledCircleNoError
\r
687 cmp cx, si ; x > y?
\r
688 ja @@FleeFlyFlowFum
\r
690 sub di, si ; error -= (2 * y)
\r
692 mov jump_vector, offset @@Advance
\r
694 @@FilledCircleNoError:
\r
696 mov jump_vector, offset @@NoAdvance
\r
707 _x_filled_circle endp
\r