Synopsis to "Graphics Programming using Assembly" by Ron Thomas


This book will provide you with all the information you need to write super-fast graphics programes in assembly. Techniques for graphics programming are developed methodically from first principles and a comprehensive set of reusable subroutines is developed as we work our way though the book. With these subroutines you will be able to:-

Over 70 tested graphics subroutines are provided, together with numerous demonstration programs and also a working library for you to use with your own programs. All assembly source code is included.

Summary of Contents

This book is aimed at readers who have some knowledge of assembly language programming and who now wish to extend their skills into the exciting and stimulating field of computer graphics. The requisite programming techniques for graphics programming are developed methodically from first principles and a comprehensive set of subroutines is descibed in the book. These can moreover be easily incorporated into users programs, for the many specific applications which require the added impact and presentation, which can only be provided by interactive computer graphics.

The book commences with a brief introduction explaining the purpose of the book and then launches into a description of the available video modes, ranging from the humble Colour Graphics Adaptor mode, to all the new modes provided by the Vesa Bios Extensions to the SVGA standard. Then starting with the most basic graphics function - the writing of a pixel onto the display screen, subroutines are described for use in all the commonly avaiable graphics modes and also for the much more versatile SVGA VBE modes.

These fundamental pixel plotting subroutines are then used to construct basic graphic primitives, such as the line, the box, the circle and the ellipse. They are all contructed in wire-frame form, in the manner of the commercial DRAW programs (this is an efficient and intuitive method for the display and manipulation of objects). Methods are also described for filling these objects with colour.

The use of the mouse in the construction of user friendly and intuitive programs is discussed with respect to the limitations of the standard mouse driver in graphics modes. Normally the mouse cannot be used at a higher resolution than 640*480, due to a limitation of the mouse driver, which is particularly frustrating, as entry level PC's are currently being provided with SVGA screens !. A solution to the problem is therefore provided in the form of a special mouse handler, which creates a special mouse cursor which is visible in all the available video modes (even the SVGA/VBE modes). This handler is then used by all the mouse dependent programs described in the book.

We then move on and develop subroutines for performing various image transforms on graphics objects, such as image rotation, image inversion and the construction of mirror images. These operations are essential to CAD programming and should therefore be of particular interest to programmers wishing to work in this area.

Techniques for constructing rectangles, squares and circles interactively using the mouse, are also covered, as are techniques for filling them with colour, i.e forming solid objects from the wire-form outline. Also we don't forget the polygon. Its interactive construction is also described, even for re-entrant shapes and a method is also provided for filling it with colour.

The construction of curves of various mathematical descriptions is also described, including the useful Bezier curve. All this shows what can be achieved in computer graphics; it also demonstrates how a maths coprocessor can be employed to speed up many calculations. (Examples of the programming of the maths coprocessor are not always included in assembly language text books). Other programs demonstrate the construction of Fractal objects such as the famous "Mandelbrot Set" and the generation of the Strange Attractors from the world of Chaos.

A topic of interest to data analysts and statisticians is provided in the form of a program for drawing of the the "Best Straight Line" through a set of experimental data points. I haven't seen this covered in any other assembly language book, so this is one other feature that makes this book that little bit different from the currently available assembly books !

Towards the end of the book, screen image processing is described and covers image inversion and the making of an in-place mirror image. A subroutine for the transfer of a displayed graphics image to a compatible laser printer is also provided, as there must be many occasions when the programmer wishes to capture his/her creations permanently onto paper !

In the last chapter there are examples of the interfacing of assembly subroutines to the high level languages Basic, "C" and Fortran. Programmers with expertise in these languages are therefore provided with the means to beef-up their slow high level applications.

The reader, is therefore provided with a broad base of many aspects of computer graphics, which will enable him, or her to make immediate use of the wide range of subroutines which are described in this book. A guide on these and a description of their calling conventions is included in Appendex B.

This summary has necessarily skipped over a lot of detail and I refer you to the Annontated Table of Contents for a full description of the books content. In addition, Chapter 5 (on line drawing), is provided for your perusal and is a sample of the graphics programming contained in the complete book.

                       Annotated Table of Contents


            Chapter 1     Introduction and Overview of the book

		      1     Introduction.
		      2     What's in the book.

            Chapter 2     Screen Display and Video modes.

            Chapter 3     Pixel Addressing.

            Chapter 4     Pixels. Reading and Writing them.

                      4.1   Pixel Writing.
                      4.2   Pixel Reading.

            Chapter 5     Drawing a Straight Line.

                      5.1   The Bresenham straight line algorithm.
		      5.2   The Michalski straight line algorithm.

            Chapter 6     Line Clipping.

			    The Cohen-Sutherland algorithm.

            Chapter 7     A special cursor for use in all
                            graphics modes.

		      7.1   Making the special mouse cursor.
		      7.2   Drawing a "rubber_band" line with the
                            aid of the mouse.
		      7.3   Hiding or revealing the special cursor.

            Chapter 8     Drawing Rectangular Objects.

		      8.1   Draw a rectangle using the mouse.
		      8.2   Draw a rectangle filled with colour.
		      8.3   Draw a true square interactively
                            using the mouse.

            Chapter 9     Pertaining to Circles.

		      9.1   The Michener-Bresenham algorithm.
	              9.2   The Paterson-Kientzle algorithm.
		      9.3   Filling the circle with colour.
	              9.4   The drawing of orthogonal circles.

            Chapter 10    Drawing Ellipses

		      10.1  A simple geometric algorithm.
		      10.11 Drawing an Ellipse using the
                            Keintzle algorithm.
		      10.2  Filling an Ellipse with colour.

            Chapter 11    Geometrical Transforms.

		       11.1 Translation.
                       11.2 Scaling.
                       11.3 Rotation.
                       11.4 General Transform using translation,
                            scaling and rotation of coordinates.

            Chapter 12    Drawing Polygons.

		      12.1  Drawing a wireframe polygon
			    interactively using the mouse.
		      12.2  Drawing a solid polygon using
			    determined vertex coordinates.
		      12.3  Drawing a symmetrical wireframe
			    polygon using the mouse.

            Chapter 13    Menu Construction.

		       13.1 Selection from a horizontal menu
			    using the mouse.

		       13.2 Selection from a two dimensional
                            menu using the mouse.

            Chapter 14    Fractals and Chaos

		      14.1  Fractals.

		      14.11 Sierpinski.
		      14.12 Cantor Circles.
   	              14.13 The Mandelbrot Set.

		      14.2  Strange Attractors.

		      14.21 The Lorenz attractor.
		      14.22 The Ikeda attractor.

            Chapter 15    Drawing Curves.

		      15.1  Drawing a Bezier curve interactively 
                            using the mouse.
		      15.2  Other mathematical curves.
		      15.21 The Lissajous Curve.
	              15.22 The Butterfly curve.

            Chapter 16    The construction of the "Best Straight
			    Line" through a set of observed data

            Chapter 17    Screen Operations.

                       17.1 Inversion of a defined area
                            of the screen.
                       17.2 Make a mirror-image in a
                            defined screen area.
                       17.3 Transfer the screen image
                            to a laser printer.

            Chapter 18    High Level Language Interfaces.

		       18.1 The BASIC - Assembly Interface.
 		       18.2 The "C" - Assembly Interface.
 		       18.3 The Fortran - Assembly Interface.





            Appendix A    Use of the MASM Utilities.

        	        A.1 MASM (Assemble the program)
                        A.2 CREF (Create a cross reference listing)
		        A.3 LINK (Form a executable program)
		        A.4 Codeview   (Debugging the program)
                        A.5 LIB  (Library management)

            Appendix B    A list of all the Subroutine Calls.

		        B.1 A list of all the subroutines
                            contained in the library GLIB.LIB
		        B.2 Details of the subroutines calling

            Appendix C    Listings of useful ancillary

            Appendix D    A list of all the source files
                            described in the book.
		        D.1 List of the source files.
		        D.2 List of the executable files.
		        D.3 List of the other files.

            Appendix E    The Vesa Bios Extension Modes.

                         E1 The Vesa Bios Extension Subfunctions
                         E2 A useful graphics card interrogation
                            program SVGAINFO for the SVGA VBE modes.

Chapter 5

Drawing a Straight Line

In Chapter 4 we established how we could write a pixel to the video memory, (i.e. the screen display) and we now move on to the drawing of the much used graphics primitive - the straight line. This is often used on in its own, but it is also needed to build other graphics objects, such as the the square, the rectangle and the polygon. The construction of the straight line is therefore an important and indispensable operation in graphics programming.

But how is it actually done ? Manually we can place a rule on a piece of paper and draw a straight line along its edge. But this is only a replication operation and obviously we can't use the same technique to draw a line of pixels onto the computer screen. A mathematical solution is used instead, in which we represent the straight line by a set of pixels which are located as near as possible to the line defined by its end point coordinates (X1,Y1) and (X2,Y2). It is in fact, a visual approximation of the mathematical line, and the higher the screen resolution, the nearer the line will approach the ideal line. Fig 5.1 shows a magnified section of a typical line, in which the black dots represent the position of the plotted pixels and the ideal line (unseen on the monitor) is represented by the continuous line.

The simplest method of predicting the position of the pixels is to calculate the slope of the line, which is given by (Y2-Y1)/(X2-X1). We can then find any position Y, corresponding to the independent variable X, using the standard equation Y = a + b*X , where a is the intercept with the Y axis and b is the slope. This is very easy to program, but because it uses floating point instructions, is inherently slow. Graphics programmers have therefore devised various ingenuous algorithms, which will calculate the straight line using integer arithmetic only. Although these algorithms are a little more complex, they are nether the less much faster than the floating point version and are used today in most fast graphics programs. One of the early pioneers of these fast algorithms was J.E.Bresenham (Ref 24) and many of the subsequent algorithms are variations of his method, so we will look first at this useful and classic algorithm.

5.1  The Bresenham Straight Line Algorithm

Bresenham observed that a line with slope greater than or equal to zero, and less than or equal to one, would intersect the next vertical grid line at a point P. Two vertically arranged pixels straddle P, and the one which is nearest is the pixel which should be plotted. Thus, referring again to Fig 5.1, if (s - t) < 0 we choose pixel A, or if (s - t) > 0 we choose pixel B, which means the decision on choice of pixel can be made on the sign of the difference (s - t). The nub of the algorithm is therefore the method that Bresenham used to determine this decision sign. He first makes a one time calculation of two variables, which we will call INCR1 and INCR2 in Listing 5.1. These are evaluated as follows:-

         dx    = abs(X2 - X1)
         dy    = abs(Y2 - Y1)
         incr1 = 2 * dy
         incr2 = 2 * (dy - dx)
A third variable DECISION is used as the decision variable and this is initialised as follows:-

         decision = 2*dy - dx
The code is then split into two parts, which deal the cases where the slope is greater than or less than one. If its greater than one, then incrementing the dependent variable X will result in an increment in Y greater than one. So for this case we reverse the role of X and Y. In both cases there is a small inner loop in which the algorithm loops through the integral values of X, (or Y for the case where slope > 1) and the decision variable is compared with zero and the appropriate pixel is plotted. For a detailed explanation of the algorithm refer to the original paper, or to Foley and Van Dam's book on "The Fundamentals of Interactive Computer Graphics" (Ref 8). This algorithm is very fast and adequate for most purposes, but it is in fact possible to speed it up further, by applying the incremental changes in the pixel position directly to the addresses in the video memory. To do this properly however, you must always check which memory bank the pixel resides in and switch to it before issuing the instruction to replace, or XOR the pixel at its location in video memory.

Listing 5.1

.MODEL small    ; Listing 5.1   ; Source file is LINE.ASM

X1              EQU     [si]    ; Coordinates of the line
Y1              EQU     [si+2]  ; contained in the calling
X2              EQU     [si+4]  ; pgm's parameter block
Y2              EQU     [si+6]
colour          EQU     [si+8]
plotadot        EQU     [si+14] ; Address of dot plotting routine
;-------------------------------; End of parameter block

decision        sword   ?       ; The decision variable
delta_x         dw      ?
delta_y         EQU     delta_x
incr1           dw      ?       ; Increment 1
incr2           dw      ?       ; Increment 2
xend            sword   ?       ; Line end point
yend            EQU     xend
xinc            dw      ?       ; X increment
yinc            EQU     xinc

        PUBLIC  line
; Draws a straight line using Bresenham's algorithm     ;
;               Valid for all slopes.                   ;
;                                                       ;
; Entry:        si points at parameter block            ;
line    proc    USES ax bx cx dx di bp

        mov     al,colour       ; Get the colour attribute

        mov     bx,X1
        sub     bx,X2           ; Get absolute difference
        jns     short   got_dx  ; for X2 - X1
        neg     bx
got_dx: mov     delta_x,bx      ; Save delta_x

        mov     cx,Y1
        sub     cx,Y2           ; Get absolute difference
        jns     short   got_dy  ; for Y2 - Y1
        neg     cx
got_dy: mov     delta_y,cx      ; Save delta_Y

        cmp     cx,bx           ; Test the slope.
                                ; Is delta_Y greater
        jae     slope_more_1    ; than delta_X
                                ; i.e the slope is GE 1

; This section handles lines with slopes less than 1

        shl     cx,1            ; 2 * delta_Y
        mov     incr1,cx        ; increment1 for case d < 0

        sub     cx,bx           ; 2 * delta_Y - delta_X
        mov     decision,cx     ; initial decision variable

        sub     cx,bx           ; 2 * (delta_Y - delta_X)
        mov     incr2,cx        ; increment2 for case d >= 0

        mov     di,X1           ; Take copy of 1st points coords
        mov     bp,X2

.IF     di  GT  bp              ; If X1 larger X2

        mov     bx,Y1
        mov     cx,X2
        mov     dx,Y2
        mov     xend,di         ; Set end of line, xend = X1

        .IF     delta_y == 0
                mov     yinc,0
                .IF     dx GT bx         ; Is Y2 larger Y1 ?

                        mov     yinc,-1
                        mov     yinc,1
        mov     bx,Y2
        mov     cx,X1
        mov     dx,Y1
        mov     xend,bp                  ; Set xend = X2

        .IF     delta_y == 0
                mov     yinc,0
                .IF     bx GT dx         ; Is Y2 larger Y1 ?

                        mov     yinc,1
                        mov     yinc,-1
        ; The plotting routine is entered with coordinates
        ; X & Y in cx & dx; & colour attribute in al. Note
        ; that the bx register is altered by the routine.

        call    plotadot        ; Plot the first point

        mov     bp,incr1        ; Set regs with the 2 increments
        mov     di,incr2

.WHILE  cx LT xend              ; While X less xend

        inc     cx              ; Increment X
        .IF     decision LT 0

                add     decision,bp  ; Choose Si,no change in Y

        .ELSE                   ; else choose Ti, Y incremented

                add     dx,yinc         ; Increment Y
                add     decision,di

        call    plotadot        ; Plot all other points

        ret                     ; Return to DOS

;       Here we handle lines with slopes GE 1


        shl     bx,1            ; 2 * delta_X
        mov     incr1,bx        ; increment1 for case d < 0

        sub     bx,cx           ; 2 * delta_X - delta_Y
        mov     decision,bx     ; initial decision variable

        sub     bx,cx           ; 2 * (delta_X - delta_Y)
        mov     incr2,bx        ; increment2 for case d GE 0

        mov     di,Y1
        mov     bp,Y2

.IF     di  GT  bp              ; If Y1 larger Y2

        mov     bx,X1
        mov     cx,X2
        mov     dx,Y2
        mov     yend,di         ; Set end of line, yend = Y1

        .IF     delta_x == 0
                mov     xinc,0
                .IF     cx GT bx         ; Is X2 greater X1 ?
                        mov     xinc,-1
                        mov     xinc,1

        mov     bx,X2
        mov     cx,X1
        mov     dx,Y1
        mov     yend,bp                 ; yend = Y2

        .IF     delta_x == 0
                mov     xinc,0
                .IF     bx GT cx         ; Is X2 larger X1 ?
                        mov     xinc,1
                        mov     xinc,-1

        call    plotadot        ; Plot the first point (cx,dx)

        mov     bp,incr1        ; Set regs with the 2 increments
        mov     di,incr2

.WHILE  dx  LT  yend            ; While Y less Yend

        inc     dx              ; Increment Y
        .IF     decision LT 0

                add     decision,bp ; Choose Si, no change in X

        .ELSE                   ; else choose Ti, X incremented

                add     cx,xinc ; Increment X
                add     decision,di

        call    plotadot        ; Plot all other points (Xn,Yn)


        ret                     ; Return to DOS
line    endp

Listing 5.1  Straight line code using the Bresenham algorithm

To test the line drawing subroutine LINE at various screen resolutions we use the program shown in Listing 5.2. On starting you are prompted for a standard video mode. Please enter your choice in decimal form, but if you prefer you can give a null entry and the default video mode 6 with resolution 640*200 will be used. The same line drawing subroutine can also be used with the much more useful SVGA VBE video modes. You just use the SET_VBE_MODE routine instead of the standard SET_V_MODE routine.

Listing 5.2

.model small    ; Listing 5.2   ; Source file is TESTLINE.ASM
        EXTRN   write_string:proc,read_string:proc
        EXTRN   line:proc,asci2bin:proc,set_v_mode:proc
CR      EQU     0Dh
LF      EQU     0Ah
mode    db      0               ; Video mode
video_memory    dw      ?
parmblock       dw      4       ; Starting column
                dw      2       ; Starting row
                dw      638     ; End column
                dw      198     ; End row
                db      1       ; Colour. 0,1 for 640*200
                                ; 0-3 for 400*200
                db      0FFh    ; Plotting pattern for full line
                dw      0       ; Not used
                dw      0       ; Not used
routine_address dw      ?
pixels_per_line dw      ?
bytes_per_line  dw      ?
number_of_lines dw      ?
                dw      0       ; 0 = replace, 2 = XOR
                dd      ?
                dw      ?
                dw      ?       ; End of the parameter block

Illegal_no      db      CR,LF,'Illegal Number$'
Illegal_mode    db      CR,LF,'Illegal Mode$'

prompt1 db      CR,LF,'Starting column:$'
prompt2 db      CR,LF,'Starting row:$'
prompt3 db      CR,LF,'End column:$'
prompt4 db      CR,LF,'End row:$'
prompt5 db      CR,LF,'Colour:$'

prompt  dw      prompt1
        dw      prompt2
        dw      prompt3
        dw      prompt4
        dw      prompt5

kb_buffer       db      64,0    ; Keyboard buffer
                db      64      DUP (?)

mode_prompt     db      CR,LF,'Video Mode in decimal:$'
video_mode      db      6       ; Default is 640*200 2 colour

start:  MOV     AX,DGROUP       ; Make Data Segment addressable,
        MOV     DS,AX           ; set DS to point to data

        mov     ah,0Fh          ; Get video state
        int     10h
        mov     mode,al         ; Save mode

        xor     bx,bx
        mov     cx,5            ; Set to loop 5 times
again:  mov     dx,[prompt+bx]
        call    write_string    ; Prompt for variable
        lea     dx,kb_buffer    ; Point at keyboard buffer
        call    read_string     ; Get input from keyboard
        cmp     [kb_buffer+1],0 ; Check we got some data
        je      skip            ; Skip to next param if nul
        call    asci2bin        ; Convert ASCII chars to binary no
        jnc     ok
        lea     dx,illegal_no
        call    write_string
        jmp     fin

ok:     mov     parmblock[bx],ax; Set the variable
skip:   add     bx,2
        loop    again

        lea     dx,mode_prompt  ; Now prompt & setup the required
        call    write_string    ; video mode
        lea     dx,kb_buffer
        call    read_string
        cmp     [kb_buffer+1],0 ; If nul
        je      skip2           ; use default video mode 6
        call    asci2bin
        jnc     ok2
        lea     dx,illegal_no
        call    write_string
        jmp     fin
ok2:    mov     video_mode,al

skip2:  mov     ah,0
        mov     al,video_mode   ; Set up the video mode

        call    set_v_mode      ; Set plotting routine
        jnc     ok3             ; and the video memory
        lea     dx,illegal_mode
        call    write_string
        jmp     fin
ok3:    mov     number_of_lines,ax
        mov     pixels_per_line,cx
        mov     routine_address,dx
        mov     video_memory,es

        mov     bx,cx           ; Convert pixels/line > bytes/line
        shr     bx,3
        mov     bytes_per_line,bx

        lea     si,parmblock    ; Point at the parameter block

        call    line            ; Draw the line

        mov     ah,1
        int     21h             ; Wait for a keypress

        mov     al,mode
        mov     ah,0
        int     10h             ; Restore original mode

FIN:    MOV     AH,4Ch
        INT     21H             ; Return to DOS

        END     start

Listing 5.2  Draws a straight line using Breshenhams algorithm

5.2  The Michalski Straight Line Algorithm

Whilst Bresenham's algorithm is perhaps the most widely used, there are other useful line drawing algorithms and the algorithm by Michalski, (Refs 25,26) is certainly on par with Bresenham, at least in the tests I did. I came across a worked example of his algorithm on a bulletin board and noticed that it had a little extra coding which permits the easy drawing of non continuous, or dotted lines. There is also provision to draw a subset of the line, or to skip a defined part of the line, which could be useful in some applications. The authors name was not contained in the downloaded file, so I acknowledge his original coding which I have modified and expanded to fit in better with my suite of pixel plotting subroutines. On inspection you will see that part of the code section is self modifying, that is, some instructions are changed by previous code. I don't pretend to understand exactly whats going on here, but suspect its the key to the codes speed. I present it for what it is, a useful alternative algorithm.

Incidentally the part of the code that draws the interrupted line, could if required, be incorporated in the Bresenham algorithm as the graphics parameter block we use is general and will allow the necessary data to be set there for use by the handling subroutine. My preference however is to keep Bresenham's algorithm as fast as possible and to use the DRAWLINE algorithm when I have need for its other facilities. Documentation on the calling convention, is contained in GLIB.HTML, as it is for all the routines in this book.

Listing 5.3

.MODEL small    ; Listing 5.3 ; Source file is DRAWLINE.ASM

;       Self-modifying program implements fast-vector algorithm
;       described by Michalski, Doctor Dobb's Journal #74, 12/82
;       see also: FAST-LINE DRAWING TECHNIQUE, BYTE, Aug 81

skip_count      dw      ?       ; Copy held here

; Equates to variables in calling pgm's parameter block

x1      equ     word ptr [si]    ; Line coordinates
y1      equ     word ptr [si+2]  ;      "
x2      equ     word ptr [si+4]  ;      "
y2      equ     word ptr [si+6]  ;      "
colour  equ     byte ptr [si+8]  ; Colour attribute
pattern equ     byte ptr [si+9]  ; Repetition pattern for
                                 ; drawing the line
len     equ     word ptr [si+10] ; Line length
skip    equ     word ptr [si+12] ; Skip length
plotadot equ    word ptr [si+14] ; Address of the fast dot
                                 ; plotting routine

; These are values that will be overlayed in the code

inc_x  EQU  41h
dec_X  EQU  49h
inc_Y  EQU  42h
dec_Y  EQU  4Ah

; These are the addresses where new code is overlayed

adj_long_axis   EQU     BYTE PTR CS:[DI]
adj_master      EQU     WORD PTR CS:[DI+3]
test_master     EQU     WORD PTR CS:[DI+7]
alt_adj_master  EQU     WORD PTR CS:[DI+13]
adj_shrt_axis   EQU     BYTE PTR CS:[DI+15]

; Routine draws a line between coordinates X1,Y1 & X2,Y2        ;
;                                                               ;
; ENTRY:                                                        ;
;       DS:SI   Points at the parameter block, where            ;
;                                                               ;
;     si+0   = x1     starting horizontal pixel position        ;
;     si+2   = y1     starting vertical pixel position          ;
;     si+4   = x2     ending HPP                                ;
;     si+6   = y2     ending VPP                                ;
;     si+8   = colour attribute                                 ;
;     si+9   = line plotting bit pattern.                       ;
;               033h=00110011b, a dotted line     .. .. ..      ;
;               055h=01010101b, a dotted line     . . . . .     ;
;               077h=01110111b, a dashed line     - - - - -     ;
;               0Fh =00001111b, a long_dash line  ---   ---     ;
;               0FFh=11111111b, a continuous line  ---------    ;
;                                                               ;
;     si+10  = length                                           ;
;              0    = draw entire line                          ;
;              else = draw sub- or super-set of this vector     ;
;     si+12  = skip length                                      ;
;              number of pels to go before starting to draw     ;
;              0    = draw entire line                          ;
;     si+14  = address of the dot plotting routine              ;
;                                                               ;
;       ES      Points to start of video memory                 ;

DRAWLINE PROC   USES    ax bx cx dx di bp

        mov   bl,inc_x          ; assume xstep = +1
        mov   ax,x2
        sub   ax,x1
        jge   short dl1         ; if x1 LE x2 then no change
        mov   bl,dec_x          ; xstep = -1
        neg   ax                ; Xdist = ABS(Xdist)

dl1:    mov   cx,ax             ; save Xdist

        mov   bh,inc_y          ; assume ystep = +1
        mov   ax,y2
        sub   ax,y1
        jge   short dl2         ; if y1 LE y2 then no change

        mov   bh,dec_y          ; ystep = -1
        neg   ax                ; Ydist = ABS(Ydist)

dl2:    mov   dx,ax             ; save ydist

        mov   di,offset CS:modify_base  ; point to the code
                                        ; to modify
        cmp   dx,cx             ; determine longest axis
        jge   short dl3         ; Y is longer, so skip

        xchg  cx,dx             ; swap xdist, ydist
        xchg  bl,bh             ; swap inc/dec X/Y values

                                ; MODIFY:
dl3:    mov   adj_long_axis,bh  ; the 1st inc/dec code
        mov   adj_master,cx     ; Main duty master adjustment
        shr   cx,1              ; Set up cycle tester
        mov   test_master,cx    ; Test for cycling
        mov   alt_adj_master,dx ; Alternate adjustment
        mov   adj_shrt_axis,bl  ; Alternate inc/dec code

        mov   di,dx             ; di is counter: Long axis length
        cmp   len,0             ; if length greater than 0
        je    short dl4
        mov   di,len            ; Then use it as counter

dl4:    mov   cx,skip           ; Get skip count
        mov   skip_count,cx     ; Store a copy
        mov   cx,X1             ; Get other arguments
        mov   dx,Y1
        mov   al,colour
        xor   bx,bx             ; Duty master starts = 0

        mov   bp,bx             ; Change to BP as BX is used by
                                ; the fast dot plotting routines
                                ; to return the display offset;
                                ; not used here,but may be used by
                                ; other routines

        mov     ah,pattern      ; Get pattern into reg for fast access

;------ Top of the Vector plotting loop -------

dl5:    cmp   skip_count,0      ; Test skip count
        je    short ok_plot
        dec   skip_count
        jmp   short     no_plot

ok_plot:test  ah,1              ; Is bit 0 set
        jz    short skip_a_dot  ; Don't plot if not

        call  plotadot  ; plot a dot using appropriate subroutine

        cmp     pattern,0FFh    ; Is the line continuous ?
        je      short   no_plot
        ror     ah,1            ; Rotate the pattern 1 bit to the
                                ; right ready for next dot plot.
                                ; In this way the pattern
                                ; automatically repeats

; Most of the following code is modified by the previous sequence.
;       The 1111h's are dummy values that are always overlaid.

modify_base     label   byte

no_plot:inc   cx        ; inc/dec cx/dx: Adjust long axis ptr
        add   bp,1111h  ; xdist or ydist: Adjust duty master
        cmp   bp,1111h  ; ydist or xdist: Check cycle position
        jle   short dl6 ; skip if short axis is still OK

        sub   bp,1111h  ; xdist or ydist: Adjust duty master
        inc   dx        ; inc/dec dx/cx: Adjust short axis ptr

dl6:    dec   di        ; di is used as a counter
        jge   short dl5 ; do next dot if not finished



Listing 5.3  Straight line code using the Michalski algorithm

5.3  The Draw Line-To Subroutine

A common requirement in graphics programs is the need to draw a sequence of lines, in which the end location of one line is the start location of the next; as in polygon drawing for instance. The following subroutine, shown in Listing 5.4, is designed to carry out this function and makes use of a line drawing algorithm, DRAWLINE in this example, to draw a line from coordinates X1,Y1 to X2,Y2 and after completion, places the end location coordinates X2,Y2 in the start location of the graphics data block, ready for the next call of the subroutine.

The short test program TESTL_TO, shown in Listing 5.5, is a simple test of the subroutine which draws lines around the boundaries of the screen, using the preset 06h graphics mode. Note also that the lines drawn are not continuous, but are written with a repetitive pattern determined by the value 33h (or 01010101b). That is, we only plot every other pixel in the line; other patterns can also be used set simply by setting the appropriate bits in this mask. After the lines have been drawn, the DOS function 021h/01h, is used to pause the program until any key is pressed; this allows the image to be inspected.

Listing 5.4

.MODEL small    ; Listing 5.4   ; Source file is LINE_TO.ASM

x1      EQU     [si]            ; Equates to data in calling pgm
y1      EQU     [si+2]
x2      EQU     [si+4]
y2      EQU     [si+6]
colour  EQU  byte ptr   [si+8]  ; BYTE. The pixel colour

        EXTRN   drawline:proc
        PUBLIC  line_to
; Draws a line from X1,Y1 (last location) to    ;
; X2,Y2 and then copies X2,Y2 to X1,Y1 in the   ;
; parameter block ready for next call.          ;
;                                               ;
; Entry:        SI points at parameter block    ;
;                  in the calling program       ;

line_to PROC    uses    ax

        call    drawline     ; Draw line to the required location

        mov     ax,X2        ; Reset X1,Y1 ready for next call of
        mov     X1,ax        ; the routine.
        mov     ax,Y2
        mov     Y1,ax

line_to ENDP

        Listing 5.4  Draws a line from the last to the current end position

Listing 5.5
.MODEL      small ;Listing 5.5
;  Source     file       is TESTL_TO.ASM
.386 ;****  For     testing	LINE_TO	routine	**** 
EXTRN    line_to:proc,set_v_mode:proc,write_string:proc


parmblock EQU	THIS	word
X1      dw   0
Y1      dw   0
X2      dw   600
Y2      dw   0
colour 	db   1
pattern db   033h   ; 0FFh is a continuous line
        dw   0
        dw   0
routine_address	dw  ?
pixels_per_line dw  ?
bytes_per_line	dw  ?
number_of_lines dw  ?
                dw  0     ;	Replace    action
                dd  0
                dw  ?
                dw  ?	  ;  End of the parameter block
mode            db  ? 
illegal_mode	db     CR,LF,'Illegal 	Mode$'

begin:     mov  ax,DGROUP ; Set up data    segment
           mov	ds,ax
           mov  ah,0Fh
           int 10h     ; Get current video mode
           mov mode,al ; Save it
          xor	ah,ah
          mov	al,6           ;       Select mode 6 
          call  set_v_mode
          jnc	ok
          lea	dx,illegal_mode 
          call	write_string
          jmp	fin
          mov     number_of_lines,ax
          mov     pixels_per_line,cx
          mov     routine_address,dx
          mov     bx,cx          ; Convert pixels/line to  bytes/line
          shr     bx,3
          mov     bytes_per_line,bx

          lea     si,parmblock
          call    line_to         ; Draw 1st line

          mov     y2,198
          call    line_to

          mov     x2,0
          call    line_to

          mov     y2,0
          call    line_to

          mov     ah,1
          int     21h             ; Wait for keypress

          mov     al,mode
          mov     ah,0
          int     10h             ; restore orig mode

fin:      mov     ah,4Ch
          int     21h             ; Return to DOS

          end     begin

        Listing 5.5     Tests out the LINE_TO subroutine

Appendix D

The source, executable and other files contained in this book

D.1      List of all the source files

Filename Ext Length          Description of the file

ANGLE    ASM      872        Get angle, given delta y & delta x
ASC2BDS  ASM     1075        ASCII to binary.  Command line use 
ASCI2BIN ASM     1774        Convert ASCII to binary 
ASMSUB   ASM      511        For the BASIC/ASM inteface test 
BESTLINE ASM     6137        Best Straight line program 
BEZIER   ASM     5999        Bezier curve subroutine 
BLINE    ASM     4922        Best straight line for 100 points 
BLINE3   DAT      107        Data for the best straight line pgm 
BUTERFLY ASM     4243        A program to draw a butterfly curve 
CHEESE   ASM     2382        Makes a Cantor cheese fractal 
CHKEQUIP ASM     1586        Checks the equipment hardware 
CHKLINE  ASM	 1295	     Checks if a fill lines been done already 
CHORDS   ASM     2599        Symmetric chords for circle fill 
CIRCLE   ASM     1205        The Michener Breshenham algorithm 
CIRCLE2  ASM      898        The Paterson Kientzle alogorithm 
CKVESA   ASM     1199        For use in C - MASM interface test 
CLIP     ASM     4730        Clip a straight line 
DELAY    ASM      756        Produce a short delay 
DISP_DEC ASM      952        Displays a decimal number 
DRAWLINE ASM     5126        The Michalski line algorithm 
DRAW_BOX ASM     1001        Draw a rectangular box 
ELLIPSE  ASM     2898        Ellipse using Keintzle algorithm 
ELLIPSE1 ASM     2618        Ellipse using floating point code 
FDELAY   ASM      773        Time delay using a FORTRAN call 
FILLBOX  ASM     1365        Draws a box filled with colour 
FILLCIRC ASM     1432        Fill a circle routine 
FILLELPS ASM     3202        Draws a solid ellipse 
FILLPOLY ASM     8075        Draws a solid polygon 
FERN     ASM     2892        Draws a Fractal Fern 
FRAME    ASM     1064        Draw frame around the screen 
FSOUND   ASM     1450        For FORTRAN interface test 
GETCOORD ASM      702        Get mouse coordinates 
GET_NORM ASM     1969        Get the screen normalisation factor 
GET_P16  ASM     2675        Get pixel in 16 colour VBE modes 
GET_P256 ASM     1561        Get pixel in 256 colour VBE modes 
HOREFILL ASM     2555        Used in filling an ellipse 
INVERT_S ASM     2298        Inverts selected area of the screen 
IKEDA    ASM     4779        The Ikeda attractor 
LINE     ASM     4066        The Breshenham algorithm 
LINE_TO  ASM      697        Draws a line between two points 
LISSJ    ASM     4521        Draws a Lissajous curve 
LORENZ   ASM     4642        The Lorenz attractor 
MAKECIRC ASM     3177        Make a circle using the mouse 
MANDEL   ASM     4581        The Mandelbrot fractal 
MEAN     ASM      795        Calculates the mean of a F.P array 
MENU     ASM     6580        Menu selection menu using the mouse 
MENU2    ASM    13141        Select from 2D menu using the mouse 
MHANDLER ASM     6483        The mouse handler subroutine 
MIRROR_S ASM     2296        Make mirror image of selected window 
NORMWRIT ASM      534        Slow BIOS pixel write 
ORTHOG_C ASM     8851        Draw orthogonal circles. VBE mode 
PADRCGA2 ASM     1350        Get  pixel address. CGA2 pixel plot 
PADRMCGA ASM      647        Get  pixel address. MCGA pixel plot 
PADR_256 ASM     1364        Get  pixel addr. 256 colour VGA plot 
PADR_VGA ASM     1388        Get  pixel addr. 16 colour VGA plot 
PARMBLOK ASM      910        Data block for graphics subroutines 
PLOT4    ASM     1741        For  use in consructing an ellipse 
PLOTCGA2 ASM     1503        Plot pixel in CGA 2 colour mode 
PLOTMCGA ASM     1167        Plot pixel on MCGA 256 colour mode 
PLOT_256 ASM     1072        Plot pixel. Std VGA 256 colour mode 
PLOT_VGA ASM     2132        Plot pixel. Std VGA 16 colour mode 
POLYGON  ASM     2454        Subroutine to draw a polygon 
PRINTSCR ASM     4457        Send screen image to laser printer 
PUT_P16  ASM     2938        Plot pixel. VBE 16 colour modes 
PUT_P16M ASM     2023        Plot pixel. VBE 16.7m colour modes 
PUT_P256 ASM     2066        Plot pixel. VBE 256 colour modes 
PUT_P32K ASM     2049        Plot pixel. VBE 32/64k colour modes 
RESTORE  ASM      904        Restores the graphics controller 
ROTATE   ASM     2380        Rotate a cartesian coordinate 
RUBBER_B ASM     3669        Used in POLYGON construction 
SCANLINE ASM      737        Scan cmd line & advance to next char
SETBANK  ASM      630        Get the video memory bank
SETVBEM  ASM     7271        Set the Vesa Bios Extension mode
SETVMODE ASM     2927        Set a standard video mode
SHRINK   ASM     1075        Reduce DOS memory use to a minimum
SIERP    ASM     4678        Make a Sierpinski fractal
SQUARE   ASM     3960        Draws a square
SMILEY   ASM     2743        Transfers a "smiley" image to LPT2
STDMODE  ASM     2832        Demo of setting a standard mode
SVGAINFO ASM    14137        Displays information on VBE modes
SYMPOLY  ASM     4253        Make symmetric polygon with mouse
SYM_PLOT ASM     2313        For use by circle subroutine
TEMPBEZ  ASM      795        Draws a temporary Bezier curve
TEMPBOX  ASM     1881        Draws a temporary box
TEMPCIRC ASM      858        Creates a temporary circle
TEMPLINE ASM     2177        Creates a line in rubber band style
TEST16   ASM     2675        Tests the 16 colour vbe modes
TEST256  ASM     2572        Tests the 256 colour vbe modes
TESTB    ASM     1953        Test the making of a Bezier curve
TESTB2   ASM     2493        Tests the Bezier curve. VBE version
TESTB3   ASM     5472        Bezier construction using the mouse
TESTBOX1 ASM     4685        Test drawing of a rectangular box
TESTBOX2 ASM     4817        Drawing & filling box using a mouse
TESTBOX3 ASM     4682        Test the drawing of a square
TESTC2   ASM     4811        Draws a circle interactively
TESTCIRC ASM     3950        Draws concentric circles & deletes
TESTCLIP ASM     3045        Test clipping of a straight line
TESTCURS ASM     3604        Test the special cursor
TESTDPMS ASM      529        Tests Power management of VGA card
TESTELPS ASM     4143        Test the drawing of an an ellipse
TESTFEPS ASM     4329        Test filling of ellipses
TESTFILL ASM     3935        Tests circle filling
TESTFPOL ASM     5196        Tests filling a Polygon
TESTLINE ASM     2566        Tests Breshenhans line algorithm
TESTL_TO ASM     1208        Tests the Line_To function
TESTMLIN ASM     2874        Tests Michalski line alogorithm
TESTP32K ASM     2363        Tests the 32k/64k colour VBE modes
TESTP16M ASM     2392        Tests the 16m colour VBE modes
TESTPOLY ASM     4901        Test out poygon construction
TESTROT  ASM     4869        Test rotate point routine
TESTSETV ASM     1740        Tests setting of specified VBE mode
TESTSPOL ASM     4943        Test  drawing of a symetric polygon
TESTSPR  ASM     4683        Tests screen image transfer to LPT2
TESTTRAN ASM     5145        Tests the transform of coordinates
TEST_TL  ASM     4640        Test  drawing of a rubber band line
TOGGLE   ASM      891        Toggle the special cursor on/off
TRANSFM  ASM     2240        Transform coordinates by scaling, rotation and translation
VBEMODE  ASM     2808        Demo of setting a VBE routine
VESA     INC     1176        Useful include file for VBE use
WRITCHAR ASM      314        Write a character to the screen
WRITEDEC ASM      949        Write 16 bit unsigned no in decimal
WRITEHEX ASM      877        Writes a byte as 2 hex digits
WRITHEXD ASM      897        Converts nibble & write to screen

D.2      List of all the executable files

Filename Ext   Length     Description of the file

BESTLINE EXE     2528     Best Straight Line Calculation
BUTERFLY EXE     2040     The Butterfly curve
CHEESE   EXE     1366     The Cantor cheese fractal
FERN     EXE     1948     The Fractal Fern
IKEDA    EXE     1426     The Ikeda attractor
LISSJ    EXE     1546     A Lissajous diagram
LORENZ   EXE     1412     The Lorenz attractor
MANDEL   EXE     2324     The Mandelbrot fractal
MENU     EXE     2752     Select from a horizontal menu
MENU2    EXE     2974     Select from a 2 dimension menu
MOUSE    EXE    93316     MS Driver 9.00
ORTHOG_C EXE     2772     Draw an orthogonal circle
SIERP    EXE     1460     The Sierpinski fractal
STDMODE  EXE      815     Sets a standard video mode
SVGAINFO EXE     3594     Gets SVGA info on the available modes
TEST16   EXE     1562     Test  16 colour VBE modes
TEST256  EXE     1488     Test 256 colour VBE modes
TESTB    EXE     1714     The Bezier Curve
TESTB2   EXE     2304     Draw the Bezier curve using VBE modes
TESTB3   EXE     3010     Interactive Bezier curve construction
TESTBASM EXE     6692     Tests the BASIC - ASM interface
TESTBOX1 EXE     2454     Test drawing a rectangular box
TESTBOX2 EXE     2608     Draw & fill a box using the mouse
TESTBOX3 EXE     2744     Draw a square using the mouse
TESTC2   EXE     2872     Draws circle interactively with mouse
TESTCIRC EXE     2162     Draws circles in VBE mode & del by XOR
TESTCLIP EXE     1718     Tests the clipping of a straight line
TESTCURS EXE     2036     Test the special cursor
TESTCV   EXE     3530     Tests the C - ASM interface
TESTDPMS EXE      552     Test power management on a graphics card.
TESTELP1 EXE     1700     Test draws Ellipse1. A bit ragged
TESTELPS EXE     1896     Test draws the Kientzle ellipse
TESTFEPS EXE     2142     Test filling of ellipses
TESTFILL EXE     2330     Tests circle filling
TESTFPOL EXE     5438     Tests drawing a solid polygon
TESTINVS EXE     2218     Test the inversion of screen images
TESTLINE EXE     1864     Tests Breshenhams algorithm
TESTL_TO EXE     1300     Tests LINE-TO subroutine; dotted frame
TESTMIRS EXE     2228     Tests the making of a mirror image
TESTMLIN EXE     1660     Tests Michalski's algorithm
TESTP32K EXE     1442     Tests the 32k/64k colour VBE modes
TESTP16M EXE     1456     Tests 16M colour VBE modes
TESTPOLY EXE     3282     Test the construction of polygons
TESTROT  EXE     2100     Tests the rotate point function
TESTSETV EXE     1872     Tests setting & plotting of VBE modes
TESTSPOL EXE     2936     Tests drawing symmetric polygons
TESTSPR  EXE     2776     Test transfer of screen image to LPT2
TESTTONE EXE    19482     Test the FORTRAN - ASM interface
TESTTRAN EXE     2668     Tests the coordinate transform subroutine
TEST_TL  EXE     2500     Test drawing a temporary line
UNIVBE   EXE    74412     Universal Vesa Driver
VBEMODE  EXE      817     Sets a VBE mode

D.3      List of all the other files

Filename Ext    Length    Description

FORTLIB  LIB     2085     A skeleton FORTRAN library
FORTLIB  LST      464     List file for the FORTRAN library

GLIB     LIB    25625     Library containing graphics routines
GLIB     LST     8159     List file for the graphics library
GLIB     DOC    31825     Documentation file for graphics lib.

TESTBASM BAS      357     For testing the BASIC-ASM interface
TESTCV     C      273     For testing the "C" - ASM interface
TESTTONE FOR      462     For testing the FORTRAN-ASM interface