home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 03 / porter.lst < prev    next >
File List  |  1989-02-10  |  17KB  |  463 lines

  1. _GRAPHICS PROGRAMMING COLUMN_
  2. by Kent Porter
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7.    1| void far draw_line (int x1, int y1, int x2, int y2)
  8.    2|                         /* Bresenham line drawing algorithm */
  9.    3|                         /* x1, y1 and x2, y2 are end points */
  10.    4| {
  11.    5| int  w, h, d, dxd, dyd, dxn, dyn, dinc, ndinc, p;
  12.    6| register x, y;
  13.    7| 
  14.    8|   /* Set up */
  15.    9|   x = x1; y = y1;                          /* start of line */
  16.   10|   w = x2 - x1;                      /* width domain of line */
  17.   11|   h = y2 - y1;                     /* height domain of line */
  18.   12| 
  19.   13|   /* Determine drawing direction */
  20.   14|   if (w < 0) {                     /* drawing right to left */
  21.   15|     w = -w;                               /* absolute width */
  22.   16|     dxd = -1;                    /* x increment is negative */
  23.   17|   } else                           /* drawing left to right */
  24.   18|     dxd = 1;                       /* so x incr is positive */
  25.   19|   if (h < 0) {                     /* drawing bottom to top */
  26.   20|     h = -h;                       /* so get absolute height */
  27.   21|     dyd = -1;                         /* y incr is negative */
  28.   22|   } else                           /* drawing top to bottom */
  29.   23|     dyd = 1;                       /* so y incr is positive */
  30.   24| 
  31.   25|   /* Determine major axis of motion */
  32.   26|   if (w < h) {                           /* major axis is Y */
  33.   27|     p = h, h = w, w = p;       /* exchange height and width */
  34.   28|     dxn = 0;
  35.   29|     dyn = dyd;
  36.   30|   } else {                               /* major axis is X */
  37.   31|     dxn = dxd;
  38.   32|     dyn = 0;
  39.   33|   }
  40.   34| 
  41.   35|   /* Set control variables */
  42.   36|   ndinc = h * 2;                  /* Non-diagonal increment */
  43.   37|   d = ndinc - w;                /* pixel selection variable */
  44.   38|   dinc = d - w;                       /* Diagonal increment */
  45.   39|   
  46.   40|   /* Loop to draw the line */
  47.   41|   for (p = 0; p <= w; p++) {
  48.   42|     draw_point (x, y);
  49.   43|     if (d < 0) {                     /* step non-diagonally */
  50.   44|       x += dxn;
  51.   45|       y += dyn;
  52.   46|       d += ndinc;
  53.   47|     } else {                             /* step diagonally */
  54.   48|       x += dxd;
  55.   49|       y += dyd;
  56.   50|       d += dinc;
  57.   51|     }
  58.   52|   }
  59.   53| }
  60.  
  61. [LISTING TWO]
  62.  
  63. /* SPOKES.C: Bresenham demo */
  64. /* Multicolored spokes emanate from center of screen */
  65.  
  66. #include <conio.h>
  67. #include <stdio.h>
  68. #include "grafix.h"
  69.  
  70. #define CX 320            /* Center of screen */
  71. #define CY 175
  72.  
  73. void main()
  74. {
  75. int  x, y, color = 1, next (int);
  76.  
  77.   if (init_video (EGA)) {
  78.  
  79.     /* Spokes from center to top and bottom */
  80.     for (x = 0; x <= 640; x += 80) {
  81.       color = next (color);
  82.       draw_line (x, 0, CX, CY);
  83.       color = next (color);
  84.       draw_line (x, 349, CX, CY);
  85.     }
  86.  
  87.     /* Spokes from center to sides */
  88.     for (y = 70; y < 350; y += 70) {
  89.       color = next (color);
  90.       draw_line (639, y, CX, CY);
  91.       color = next (color);
  92.       draw_line (0, y, CX, CY);
  93.     }
  94.     getch();               /* Wait for a keystroke */
  95.   } else
  96.     puts ("EGA not present in system: program ended");
  97. } /* ------------------------ */
  98.  
  99. int next (int hue)    /* set/return next color */
  100. {
  101.   set_color1 (hue++);
  102.   return ((hue > 15) ? 1 : hue);  /* wrap around */
  103. }
  104.  
  105.  
  106.  
  107. [LISTING THREE]
  108.  
  109.    1| void far draw_rect (int xleft, int ytop, int w, int h)
  110.    2| /* Draw outline rectangle in color1 from top left corner */
  111.    3| /* w and h are width and height */
  112.    4| /* xleft and ytop are top left corner */
  113.    5| {
  114.    6|   draw_line (xleft, ytop, xleft+w, ytop);            /* top */
  115.    7|   draw_line (xleft+w, ytop, xleft+w, ytop+h);      /* right */
  116.    8|   draw_line (xleft+w, ytop+h, xleft, ytop+h);     /* bottom */
  117.    9|   draw_line (xleft, ytop+h, xleft, ytop);           /* left */
  118.   10| } /* ------------------------------------------------------ */
  119.   11| 
  120.   12| void far polyline (int edges, int vertex[])  
  121.   13| /* Draw multipoint line of n edges from n+1 vertices where: */
  122.   14| /*        vertex [0] = x0    vertex [1] = y0                */
  123.   15| /*        vertex [2] = x1    vertex [3] = y1                */
  124.   16| /*          etc.                                            */
  125.   17| {
  126.   18| int x1, y1, x2, y2, v;
  127.   19| 
  128.   20|   x1 = vertex[0];
  129.   21|   y1 = vertex[1];
  130.   22|   for (v = 2; v < (edges+1)*2; v+= 2) {
  131.   23|     x2 = vertex[v];
  132.   24|     y2 = vertex[v+1];
  133.   25|     draw_line (x1, y1, x2, y2);
  134.   26|     x1 = x2;
  135.   27|     y1 = y2;
  136.   28|   }
  137.   29| } /* ------------------------------------------------------ */
  138.  
  139.  
  140. [LISTING FOUR]
  141.  
  142. /* BOXES.C: Demo of draw_rect() in GRAFIX.LIB           */
  143. /* Draws a big rectangle and four smaller ones          */
  144. /* K. Porter, DDJ Graphics Programming Column, March 89 */
  145. /* ---------------------------------------------------- */
  146.  
  147. #include <conio.h>
  148. #include "grafix.h"
  149.  
  150. main ()
  151. {
  152.   if (init_video (EGA)) {
  153.     set_color1 (15);
  154.     draw_rect (100, 100, 440, 230);
  155.  
  156.     set_color1 (14);
  157.     draw_rect (110, 110, 420,  30);
  158.  
  159.     set_color1 (13);
  160.     draw_rect (110, 105, 220, 220);
  161.  
  162.     set_color1 (12);
  163.     draw_rect (340, 150, 190, 100);
  164.  
  165.     set_color1 (11);
  166.     draw_rect (340, 260, 190,  60);
  167.  
  168.     getch(); /* wait for keystroke */
  169.   }
  170. }
  171.  
  172.  
  173. [LISTING FIVE]
  174.  
  175. /* STAR.C: Draws a star using polyline */
  176.  
  177. #include <conio.h>
  178. #include "grafix.h"
  179.  
  180. int vert [] = {     /* vertices of star */
  181.   320, 60,  420,280,  150,140,
  182.   490,140,  220,280,  320, 60
  183. };
  184.  
  185. void main ()
  186. {
  187.   if (init_video (EGA)) {
  188.     polyline (5, vert);         /* draw */
  189.     getch();            /* wait for key */
  190.   }
  191. }
  192.  
  193. [LISTING SIX]
  194.  
  195. ; HLINE.ASM: Fast horizontal line drawing routine
  196. ; Uses 6845 Write Mode 0 to update 8 pixels at a time on EGA/VGA
  197. ; C prototype is
  198. ;     void far hline (int x, int y, int length_in_pixels);
  199. ; Writes in current color1 from GRAFIX.LIB
  200. ; Microsoft MASM 5.1
  201. ; K. Porter, DDJ Graphics Programming Column, March 89
  202.  
  203. .MODEL  LARGE
  204. .CODE
  205.         PUBLIC  _hline
  206.         EXTRN   _color1 : BYTE          ; Current palette reg for pixel
  207.         EXTRN   _draw_point : PROC      ; Pixel writing routine
  208.         EXTRN   _vuport : WORD          ; far ptr to vuport structure
  209.  
  210. ; Declare arguments passed by caller
  211.         x       EQU     [bp+6]
  212.         y       EQU     [bp+8]
  213.         len     EQU     [bp+10]
  214.  
  215. ; Declare auto variables
  216.         last    EQU     [bp- 2]         ; Last byte to write
  217.         solbits EQU     [bp- 4]         ; Mask for start of line
  218.         oddsol  EQU     [bp- 6]         ; # odd bits at start of line
  219.         eolbits EQU     [bp- 8]         ; Mask for end of line
  220.         oddeol  EQU     [bp-10]         ; # odd bits at end of line
  221. ; ----------------------------
  222.  
  223. _hline          PROC FAR                ; ENTRY POINT TO PROC
  224.         push    bp                      ; entry processing
  225.         mov     bp, sp
  226.         sub     sp, 10                  ; make room for auto variables
  227.         xor     ax, ax                  ; initialize auto variables
  228.         mov     last, ax
  229.         mov     solbits, ax
  230.         mov     oddsol, ax
  231.         mov     eolbits, ax
  232.         mov     oddeol, ax
  233.  
  234. ; Do nothing if line length is zero
  235.         mov     bx, len                 ; get line length
  236.         cmp     bx, 0                   ; length = 0?
  237.         jnz     chlen                   ; if not, go on
  238.         jmp     quit                    ; else nothing to draw
  239.  
  240. ; Call draw_point() with a loop if line length < 8
  241. chlen:  cmp     bx, 8
  242.         jnb     getvp                   ; go if len >= 8
  243.         mov     ax, y                   ; get args
  244.         mov     cx, x
  245. drpt:   push    bx                      ; push remaining length
  246.         push    ax                      ; push args to draw_point()
  247.         push    cx
  248.         call    _draw_point             ; draw next pixel
  249.         pop     cx                      ; clear args from stack
  250.         pop     ax
  251.         pop     bx                      ; fetch remaining length
  252.         inc     cx                      ; next x
  253.         dec     bx                      ; count pixel drawn
  254.         jnz     drpt                    ; loop until thru
  255.         jmp     quit                    ; then exit
  256.  
  257. ; Point ES:[BX] to vuport structure
  258. getvp:  mov     ax, _vuport+2           ; get pointer segment
  259.         mov     es, ax
  260.         mov     bx, _vuport             ; get offset
  261.  
  262. ; Clip if starting coordinates outside viewport
  263.         mov     cx, y                   ; get y
  264.         cmp     cx, es:[bx+6]           ; is y within viewport?
  265.         jl      checkx                  ; ok if so
  266.         jmp     quit                    ; else quit
  267. checkx: mov     ax, x                   ; get x
  268.         cmp     ax, es:[bx+4]           ; is x within viewport?
  269.         jl      remap                   ; ok if so
  270.         jmp     quit                    ; else quit
  271.  
  272. ; Map starting coordinates to current viewport
  273. remap:  add     ax, es:[bx]             ; offset x by vuport.left
  274.         mov     x, ax                   ; save remapped X
  275.         add     cx, es:[bx+2]           ; offset y by vuport.top
  276.         mov     y, cx                   ; save remapped Y
  277.  
  278. ; Clip line length to viewport width
  279.         mov     ax, es:[bx+4]           ; get vuport.width
  280.         sub     ax, x                   ; maxlength = width - starting x
  281.         add     ax, es:[bx]             ;     + vuport.left
  282.         cmp     ax, len                 ; if maxlength > length
  283.         jg      wm0                     ;   length is ok
  284.         mov     len, ax                 ;   else length = maxlength
  285.  
  286. ; Set 6845 for write mode 0, all planes enabled, color selected
  287. wm0:    mov     dx, 03CEh
  288.         mov     ax, 0005h               ; Set write mode
  289.         out     dx, ax
  290.         mov     ax, 0FF00h              ; Set/Reset reg, enable all planes
  291.         out     dx, ax
  292.         mov     ax, 0FF01h              ; Enable set/reset reg, all planes
  293.         out     dx, ax
  294.         mov     dx, 03C4h               ; 6845 address reg
  295.         mov     al, 2                   ; Data reg
  296.         mov     ah, _color1             ; Palette reg planes enabled
  297.         out     dx, ax                  ; Set color code
  298.  
  299. ; Compute x coord for last byte to be written
  300.         mov     bx, x                   ; get start of line
  301.         add     bx, len                 ; end = start + length
  302.         mov     cx, bx
  303.         and     cx, 0FFF8h              ; x coordinate where odd bits
  304.         mov     last, cx                ;   at end of line begin
  305.  
  306. ; Compute number of odd pixels at end of line
  307.         sub     bx, cx
  308.         mov     oddeol, bx              ; save it
  309.  
  310. ; Construct pixel mask for last byte of line
  311.         cmp     bx, 0   
  312.         jz      bsol                    ; go if no odd pixels
  313.         xor     ax, ax
  314. eolb:   shr     ax, 1                   ; shift right and 
  315.         or      ax, 80h                 ;   set H/O bit
  316.         dec     bl                      ;   until mask is built
  317.         jnz     eolb
  318.         mov     eolbits, ax             ; then save mask
  319.  
  320. ; Compute number of odd pixels at start of line
  321. bsol:   mov     cx, x                   ; get starting X again
  322.         and     cx, 7                   ; # of pixels from start of byte
  323.         jz      saddr                   ; go if none
  324.         mov     bx, 8
  325.         sub     bx, cx                  ; # of pixels to write
  326.         mov     oddsol, bx              ; save
  327.  
  328. ; Construct pixel mask for first byte of line
  329.         xor     ax, ax
  330. solb:   shl     ax, 1                   ; shift left and
  331.         or      ax, 1                   ;   set L/O bit 
  332.         dec     bl                      ;   until mask is built
  333.         jnz     solb
  334.         mov     solbits, ax             ; then save mask
  335.  
  336. ; Translate last byte X into an address
  337. saddr:  mov     ax, 0A000h              
  338.         mov     es, ax                  ; ES ==> video buffer
  339.         mov     bx, y                   ; get row
  340.         mov     ax, 80
  341.         mul     bx
  342.         mov     bx, ax                  ; BX = row offset = row * 80
  343.         push    bx                      ; save row offset
  344.         mov     ax, last                ; get last byte X
  345.         mov     cl, 3
  346.         shr     ax, cl                  ; shift for col offset
  347.         add     bx, ax                  ; last offs = row offs + col offs
  348.         mov     last, bx
  349.  
  350. ; Compute address of first byte (ES:[BX])
  351.         pop     bx                      ; fetch row offset
  352.         mov     ax, x                   ; get col offset
  353.         mov     cl, 3
  354.         shr     ax, cl                  ; shift right 3 for col offset
  355.         add     bx, ax                  ; offset = row offs + col offs
  356.         cmp     bx, last                ; is first byte also last?
  357.         jz      weol                    ; skip to end mask if so
  358.  
  359. ; Write start of line
  360.         mov     dx, 03CEh               ; 6845 port
  361.         mov     ah, solbits             ; start-of-line mask
  362.         cmp     ah, 0
  363.         jz      w8                      ; go if empty mask
  364.         mov     al, 8                   ; set bit mask reg
  365.         out     dx, ax
  366.         mov     cl, es:[bx]             ; load 6845 latches
  367.         mov     ax, solbits
  368.         neg     al                      ; complement
  369.         dec     al                      ;   for reversed bit mask
  370.         and     al, cl                  ; filter previously unset pixels
  371.         mov     es:[bx], al             ; clear affected bits
  372.         mov     al, _color1
  373.         mov     es:[bx], al             ; set affected bits
  374.         inc     bx                      ; next byte
  375.         cmp     bx, last                ; ready for end of line yet?
  376.         jae     weol                    ; go if so
  377.  
  378. ; Write 8 pixels at a time until last byte in line
  379. w8:     mov     ax, 0FF08h              ; update all pixels in byte
  380.         out     dx, ax                  ; set bit mask reg
  381.         mov     al, es:[bx]             ; load 6845 latches
  382.         xor     al, al
  383.         mov     es:[bx], al             ; clear all pixels
  384.         mov     al, _color1
  385.         mov     es:[bx], al             ; set all bits
  386.         inc     bx                      ; next byte
  387.         cmp     bx, last                ; thru?
  388.         jnz     w8                      ; loop if not           
  389.  
  390. ; Write end of line
  391. weol:   mov     dx, 03CEh               ; 6845 port
  392.         mov     ah, eolbits             ; end-of-line mask
  393.         cmp     ah, 0
  394.         jz      rvc                     ; go if empty mask
  395.         mov     al, 8                   ; set bit mask reg
  396.         out     dx, ax
  397.         mov     cl, es:[bx]             ; load 6845 latches
  398.         mov     ax, eolbits
  399.         neg     al                      ; complement
  400.         dec     al                      ;   for reversed bit mask
  401.         and     al, cl                  ; filter previously unset pixels
  402.         mov     es:[bx], al             ; clear affected bits
  403.         mov     al, _color1
  404.         mov     es:[bx], al             ; set affected bits
  405.  
  406. ; Restore video controller to default state
  407. rvc:    mov     dx, 03CEh
  408.         mov     ax, 0005h               ; write mode 0, read mode 0
  409.         out     dx, ax
  410.         mov     ax, 0FF08h              ; default bit mask
  411.         out     dx, ax
  412.         mov     ax, 0003h               ; default function select
  413.         out     dx, ax
  414.         xor     ax, ax                  ; zero Set/Reset
  415.         out     dx, ax
  416.         mov     ax, 0001h               ; zero Enable Set/Reset
  417.         out     dx, ax
  418.         mov     dx, 03C4h               ; 6845 address reg
  419.         mov     ax, 0F02h               ; Data reg, enable all planes
  420.         out     dx, ax
  421.  
  422. ; End of routine
  423. quit:   mov     sp, bp
  424.         pop     bp
  425.         retf
  426. _hline  ENDP
  427.         END
  428.         
  429.  
  430. [LISTING SEVEN]
  431.  
  432. void far fill_rect (int xleft, int ytop, int w, int h)
  433. /* Draw solid rectangle in color1 from top left corner */
  434. {
  435. register y;
  436.  
  437.   for (y = ytop; y < ytop+h; y++)
  438.     hline (xleft, y, w);
  439. } /* ------------------------------------------------------ */
  440.  
  441.  
  442. [LISTING EIGHT]
  443.  
  444. /* COLORS.C: Shows all colors in default palette */
  445.  
  446. #include "grafix.h"
  447. #include <conio.h>
  448.  
  449. void main ()
  450. {
  451. int r, c, color;
  452.  
  453.   if (init_video (EGA)) {
  454.     for (r = 0; r < 4; r++)
  455.       for (c = 0; c < 4; c++) {
  456.         color = (r * 4) + c;       /* next color */
  457.         set_color1 (color);
  458.         fill_rect ((c*160), (r*80), 158, 79);
  459.       }
  460.     getch();                /* wait for keypress */
  461.   }
  462. }
  463.