Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Database

Pixelmania


FEB89: GRAPHICS PROGRAMMING

Graphics programming is enthralling because it gives immediate feedback, translating your ideas into vivid visual images. It's also challenging --in many ways it's one of the most demanding forms of programming --and overcoming its complexities enhances the satisfaction of it. End users have come to expect more and better graphics, which makes the discipline increasingly important. For all these reasons and more, we embark this month on a voyage into the enchanted world of graphics programming.

In this column I'm going to discuss the whole scope of computer graphics, starting with the writing of pixels --the basic unit of visual information --and building from there. In time I'll get to such lofty subjects as shading and light sourcing and photorealism.

High-level graphics rest upon a hierarchy of lower-level functions. As a result, one of the chief projects of this column will be to develop a graphics application program interface (API), a library of routines supporting ever more sophisticated techniques for producing dazzling visual images. The API will unfold month by month, building not only a useful toolset, but also an understanding of the concepts and algorithms.

We're going to write the API in generic ANSI C, along with some assembly language routines for performance. A number of C compilers come with built-in graphics libraries, but because there's no consistency from one to the next, the API will be completely independent of any vendor's library or C dialect.

The hardware model is the EGA/VGA on IBM PCs and compatibles. Note that the CGA isn't included. The reason is simple: You can't do serious graphics development on a board that provides only four colors at low resolution. Some might say you can't on the EGA, either, which furnishes 16 out of 64 colors. While there's merit to that point, the EGA is widely available, and it provides a foundation for the VGA. Initially we'll work with the EGA, but eventually we'll move on to the VGA's much richer set of 256 colors at a time.

This puts you at a disadvantage if you're working with a different hardware environment, but it doesn't exclude you. Virtually all of the low-level machine-specific stuff will appear between now and June: routines that operate on pixels or otherwise interface directly with the video controller. Other hardware graphics systems differ in details, but all must read and write pixels. So, if you're developing on a different machine or video board, write low-level routines that parallel those presented here. Most of the higher-level functions in C can then be used "as is" to keep you in step with the column. I wish I could publish equivalent low-level routines for other systems, but if I did, I'd never get anything else done. And my purpose is, after all, to explore the meatier issues and techniques of graphics programming.

The C code written here compiles with Turbo C 2.0 and Microsoft C 5.1. For the assembly language routines, I'm using Microsoft MASM 5.1 syntax, which also assembles under Borland's TASM.

Now let's get started.

How to Write a Pixel

The elementary particle of graphics information is the pixel, a contraction for "picture element." A pixel has two characteristics: position and color.

Its position is expressed by a coordinate pair consisting of the X (or horizontal) location and the Y (vertical) position. The top left corner of the display is at {0, 0}. X coordinates increase to the right, and Y coordinates increase downward. Thus, on a display of 640x350, which is the best EGA resolution, the lower right corner of the display is at {639,349}, and the center is at {320, 175}. Note that the X coordinate is always expressed first in the pair.

Most PC-based graphics systems --the EGA, VGA, and even more exotic chips such as the TI 340X0 --use an indexed color scheme. Here, a pixel's color is not absolute but instead is taken from a set of color registers called the palette. You tell a pixel to assume a certain value. That value refers to a palette register that contains the actual color, which is a zoned bitfield containing a combination of red, green, and blue hues that comprise the color blend appearing at the pixel position. Thus, the pixel value is an index to a color register. As it refreshes each pixel, the video adapter uses the pixel value to look up the palette register where the real color is found.

In its default condition, the EGA/VGA has certain predictable values in the palette registers. For example, palette register 1 contains medium blue. Thus, PC programmers get used to thinking that 1 means blue. By changing the content of palette register 1, however, you can instantly change all pixels with value 1 to a different color.

I'll talk more about color control in April. Meanwhile, use the default palette with the understanding that a pixel value refers to a palette register, which can contain any of 64 colors. The EGA has 16 palette registers, and so does the VGA when running in EGA emulation mode; other VGA modes have 256 palette registers with a much broader selection of colors.

The simplest way to write a pixel is to call the PC's ROM BIOS video services via interrupt 10h, function 0Ch. In C notation, you might write such a call as follows:

  void draw_point (int x, int y, int pxval)
  {
  union REGS r;
       r.h.ah = 0x0C;
       r.h.al = pxval;
       r.x.cx = x;
       r.x.dx = y;
       int86 (0x10, &r, &r);
  }

To place a blue pixel in the center of the screen, then, you'd write

  draw_point (320, 175, 1);

Unfortunately, simplest is not always best. The ROM BIOS video services are shockingly inefficient. On my 10-MHz AT clone, the best throughput is a lazy 2,000 pixels per second using this C function. By going around the ROM BIOS to interface directly with the 6845 video controller using assembly language, you can achieve a 10.5X increase in throughput --to around 25,000 pixels per second --without sacrificing reliability. And in the special case discussed next month, a 250X improvement (yes, an amazing half a million pixels per second) is possible. To accomplish this miracle, it's necessary to understand something about the 6845 video controller chip (VCC) and the way pixel values are represented.

Programming 6845 Write Mode 2

Video memory in the EGA/VGA consists of color planes. There are as many color planes as there are possible bits in a pixel value. In EGA 16-color mode 10h, a pixel can have any value from 0h to 0Fh, or four bits, and thus there are four color planes.

The exact details of how this is implemented are not important, because the VCC manages it for us. What is important to realize is that pixels are grouped by byte across the width of the screen. With a horizontal granularity of 640 pixels, the display is conceptually 80 bytes wide. But under each byte are layered a number of other bytes that you can't see: in EGA mode 10h, three others for a total of four.

A pixel's value is determined by finding its bit position within the topmost byte, then peering downward through the corresponding bit positions in the other three layers. The bits comprising the pixel value are thus "stacked," with each bit on a different plane. A plane is a region of display memory: 28,000 bytes for a 640x350 display. The pixel at the top left corner derives its value from the high-order bits of the bytes at offsets 0, 28,000, 56,000, and 84,000.

At first glance, such a scheme makes you wonder how much the designers had to drink before they dreamed it up. Closer examination, however, reveals the method of the madness: You can add another color plane simply by tacking an additional 28,000 bytes onto the end of the display memory, without rearranging the mapping of bytes to pixels.

The 6845 VCC takes care of all the bit-twiddling required to read and write pixels. By writing a series of values to the VCC via ports in the range 3C4h through 3CEh, you program the 6845 to perform certain pixel-oriented operations. Once you've programmed the VCC, read from or write to the pixel's plane 0 video buffer address, and the VCC transparently intervenes to perform the plane indexing.

In order to update individual pixels, set up the VCC for Write Mode 2. It's also necessary to load a bit mask specifying the pixel(s) within the byte (which represents eight pixels) to be updated. Then read the pixel's byte location in plane 0 of the video buffer. This loads the four plane bytes into the 6,845 latch registers. By writing 0 to the video buffer address, you clear the mask-specified pixel(s); then you write the new palette register value to the same address. The VCC updates the affected bits in the latch registers and copies the latches back to their proper memory locations. The pixel change takes effect instantly.

Listing One, page 142, is the low-level assembly language routine DRAWPT. ASM, which performs this 6845 VCC interface function. It's written to be called from C with the prototype

  void far draw_point (int x, int y);

As mentioned earlier, this function achieves over ten times the performance of the ROM BIOS equivalent.

Note that public and external symbols must be prefixed in assembly language with an underscore. This complies with C linkage conventions. Note also that DRAWPT.ASM relies on an external variable called color1 to furnish the new pixel value. I discuss where that variable comes from next.

Starting the GRAFIX API

The development of a graphics API begins with the bare-bones library of four functions described in GRAFIX.H (Listing Two, page 146). These functions are:

  • Put the video system into a graphics mode.
  • Restore the system to its original text mode.
  • Write a pixel.
  • Select the current pixel value.

Of these functions, one is a separate program (DRAWPT.ASM from Listing One), while the other three are found in GRAFIX.C (Listing Three, page 146). After assembling DRAWPT.ASM and compiling GRAFIX.C, create a library with the DOS utility command

  LIB GRAFIX + GRAFIX+DRAWPT;

This pulls GRAFIX.OBJ and DRAWPT. OBJ into the single object file GRAFIX.LIB, with which you can link your application programs.

Let's briefly discuss the elements in GRAFIX.C. The init_video( ) function places the graphics subsystem into the mode specified via the argument. The two modes currently supported are EGA and VGA16, defined in GRAFIX.H. This function does a number of things, as its length suggests.

Lines 46 - 76 inventory the video subsystem. Jeff Duntemann's first column arrived as I was writing this routine. By a happy coincidence it contained a method for detecting the video equipment that's simpler than mine, so I adapted Jeff's code to suit. For more on how it works, see the "Structured Programming" column in this issue. Note that the VGA emulates EGA modes, so both the ega and vga variables are set to TRUE when a VGA is detected.

Assuming that an EGA or VGA is present, lines 78 - 98 perform a number of set-up operations:

  • Select the default pixel color.
  • Save the current text mode, video page, and cursor position.
  • Copy the text screen to a save area on the heap so that it can be restored intact later when you return from graphics mode.

Lines 97 - 109 then switch the system to graphics, providing that the desired mode is supported. Success is indicated by setting the result variable to TRUE. Lines 110 - 117 check the result and either deallocate the text screen save area when unsuccessful or save the graphics mode and register pc_textmode( ) as an exit function when the system has been put into graphics. The function returns the result variable so that the caller can find out if the call succeeded.

init_video( ) is by far the most complex function in the library, and it will probably remain so. But we're not done with it yet. In later installments I'll expand it to accommodate new video modes, as well as to initialize the color palette and a data structure describing the display characteristics. It's complete enough for now, though.

The function pc_textmode( ) restores the graphics system to its original state, with the screen as it was prior to invoking graphics and the cursor correctly placed. This function runs only if the system is in graphics; the oldmode variable is always 0 (FALSE) when in text mode, and something else when in graphics. There's a reason: init_video( ) registers, pc_textmode( ) as an exit function, which is automatically called on program termination. There is no C function to undo the atexit( ) call, so pc_textmode( ) will be called when the program ends no matter what. If you were already in text mode and this safeguard didn't exist, the call to pc_textmode( ) would crash the system or corrupt the display.

The final function is set_color1. It simply stores the argument --the currently-selected palette register for pixels --into the color1 variable. This variable is used by the pixel-writing routine and will also be used by the fast line-drawing routines to be presented next month.

The GRAFIX library is an absolute minimal API. Though it lacks functionality, it can be made to do some useful work. The STRIPES.C program (Listing Four, page 146) furnishes a small program that you can use to test your copy of the library. The program draws a solid rectangle in the center of the display with multicolored stripes running northeast to southwest. It freezes the display until you press a key and then restores the original text screen. After compiling the program, link it with GRAFIX.LIB and the runtime library for the compiler and memory model.

Must Reading for PC Graphics Programmers

If you do much graphics programming, a necessary addition to your reference bookshelf is Richard Wilton's Programmer's Guide to PC & PS/2 Video Systems, published by Microsoft Press in 1987. This book could almost be subtitled "More Than Anyone Would Ever Want to Know About..." Its 531 pages bulge with excruciatingly detailed information about the CGA, MCGA, EGA, VGA, and Hercules, including numerous listings in assembly language and a fair number in C as well. Wilton presents alternative algorithms for such challenging problems as drawing circles and doing flood fills, with lucid discussions of which is best for a given circumstance. My copy is getting dogeared from heavy use, and the only criticism I have so far is that the listings are in faded green, which is hard to read. This book is just super.

So there we have it, the modest beginnings of an epic voyage into the infinitely fascinating innards of graphics programming. I invite you to rejoin me here each month as we explore the crystal caverns of this magical craft.

_Graphics Programming Column_ by Kent Porter

[LISTING ONE]

<a name="0076_0009">

; DRAWPT.ASM: Writes pixel directly to 6845 Video Controller
; Microsoft MASM 5.1
; C prototype is
;      void far draw_point (int x, int y);
; To be included in GRAFIX.LIB
; K. Porter, DDJ Graphics Programming Column, February '89

.MODEL  LARGE
.CODE
        PUBLIC  _draw_point
        EXTRN   _color1 : BYTE          ; From GRAFIX.LIB
x       EQU     [bp+6]                  ; Arguments passed from C
y       EQU     [bp+8]

_draw_point     PROC FAR
        push    bp                      ; Entry processing
        mov     bp, sp

; Point ES to video memory segment
        mov     ax, 0A000h
        mov     es, ax

; Row offset = y * 80;
        mov     bx, y                   ; Get y argument
        mov     ax, 80
        mul     bx                      ; Result in AX
        mov     bx, ax                  ; Row offset in BX

; Column offset = x SHR 3
        mov     ax, x                   ; Get x
        mov     cl, 3                   ; Shift operand
        shr     ax, cl                  ; Column offset

; Complete address of pixel byte
        add     bx, ax                  ; ES:BX = address

; Build bit mask for pixel
        mov     cx, x                   ; Get x again
        and     cx, 7                   ; Isolate low-order bits
        xor     cl, 7                   ; Number of bits to shift
        mov     ah, 1                   ; Start bit mask
        shl     ah, cl                  ; Shift for pixel
        mov     cl, ah                  ; Save it

; Use write mode 2 (single-pixel update)
        mov     dx, 03CEh               ; 6845 command register
        mov     al, 5                   ; Specify mode register
        mov     ah, 2                   ; Write mode 2
        out     dx, ax                  ; Send

; Set 6845 bit mask register
        mov     al, 8                   ; Specify bit mask register
        mov     ah, cl                  ; al = mask
        out     dx, ax                  ; Send bit mask

; Draw the pixel
        mov     al, es:[bx]             ; Load 6845 latch registers
        xor     al, al                  ; Clear
        mov     byte ptr es:[bx], al    ; Zero the pixel for replace
        mov     al, _color1             ; Get the pixel value
        mov     es:[bx], al             ; Write the pixel

; Restore video controller to default state
        mov     dx, 03CEh
        mov     ax, 0005h               ; write mode 0, read mode 0
        out     dx, ax
        mov     ax, 0FF08h              ; default bit mask
        out     dx, ax
        mov     ax, 0003h               ; default function select
        out     dx, ax
        xor     ax, ax                  ; zero Set/Reset
        out     dx, ax
        mov     ax, 0001h               ; zero Enable Set/Reset
        out     dx, ax
        mov     dx, 03C4h               ; 6845 address reg
        mov     ax, 0F02h               ; Data reg, enable all planes
        out     dx, ax

; Exit
        mov     sp, bp
        pop     bp
        retf
_draw_point     ENDP
                END

<a name="0076_000a"><a name="0076_000a">
<a name="0076_000b">
[LISTING TWO]
<a name="0076_000b">

 /* Library source file GRAFIX.C               */
 /* EGA/VGA graphics subsystem                 */
 /* Following library routines are external:   */
 /*     DRAWPT.ASM       Feb '89               */
 /* K. Porter, DDJ Graphics Programming Column */
 /* ------------------------------------------ */

 #include <dos.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include "grafix.h"

 #if !defined TRUE
 #define FALSE 0
 #define TRUE  !FALSE
 #endif

 /* Variables global to this library */
 int  color1,                            /* foreground color */
      oldmode = 0,                      /* pre-graphics mode */
      grafixmode = 0,               /* default graphics mode */
      ega = FALSE,                     /* equipment Booleans */
      vga = FALSE,
      colormonitor = FALSE,
      curpos,                        /* text cursor position */
      textpage;                          /* active text page */
 unsigned vidmem;                    /* video buffer segment */
 char far *vidsave;                /* video buffer save area */

 /* -------------------------------------------------------- */

 int far init_video (int mode)

 /* Initializes video adapter and defaults for mode          */
 /* Sets up pc_textmode() to be called on pgm termination    */
 /* Returns TRUE or FALSE indicating success                 */
 /* This function will be expanded in a later version        */
 {
 union REGS r;
 int result = FALSE;

   /* Determine attached adapter and monitor */
   r.h.ah = 0x1A;                    /* VGA inquiry function */
   r.h.al = 0;
   int86 (0x10, &r, &r);                    /* ROM BIOS call */
   if (r.h.al == 0x1A)
     switch (r.h.bl) {
       case 4 : ega = TRUE;                     /* EGA color */
                colormonitor = TRUE;
                break;
       case 5 : ega = TRUE;                      /* EGA mono */
                break;
       case 7 : ega = TRUE;                      /* VGA mono */
                vga = TRUE;
                break;
       case 8 : ega = TRUE;                     /* VGA color */
                vga = TRUE;
                colormonitor = TRUE;
     }
   else {                        /* No VGA, so check for EGA */
     r.h.ah = 0x12;
     r.x.bx = 0x10;
     int86 (0x10, &r, &r);
     if (r.x.bx != 0x10) {              /* if EGA present... */
       ega = TRUE;                               /* set flag */
       r.h.ah = 0x12;
       r.h.bl = 0x10;              /* find out which monitor */
       int86 (0x10, &r, &r);
       if (r.h.bh == 0)
         colormonitor = TRUE;                   /* EGA color */
     }
   }

   /* Proceed only if EGA or VGA present */
   if (ega | vga) {
     set_color1 (15);                 /* default pixel color */

     r.h.ah = 0x0F;               /* get current screen mode */
     int86 (0x10, &r, &r);
     oldmode = r.h.al;                           /* store it */
     textpage = r.h.bh;             /* also active text page */

     if (colormonitor)              /* point to video memory */
       vidmem = 0xB800;
     else
       vidmem = 0xB000;
     vidsave = malloc (4096);          /* allocate save area */
     movedata                   /* save text screen contents */
         (vidmem, 0, FP_SEG (vidsave), FP_OFF (vidsave), 4096);

     r.h.ah = 3;                 /* get text cursor position */
     r.h.bh = textpage;
     int86 (0x10, &r, &r);
     curpos = r.x.dx;                         /* and save it */

     if ((mode == EGA) && ega) {
       r.h.ah = 0;
       r.h.al = mode;                        /* set EGA mode */
       int86 (0x10, &r, &r);
       result = TRUE;
     } else
       if ((mode == vga) && vga) {
         r.h.ah = 0;
         r.h.al = mode;
         int86 (0x10, &r, &r);
         result = TRUE;
       }
   }
   if (!result) {            /* unable to switch to graphics */
     oldmode = 0;              /* so cancel text screen save */
     free (vidsave);
     vidsave = 0;
   } else {                             /* successful, so... */
     grafixmode = mode;                         /* save mode */
     atexit (pc_textmode);         /* register exit function */
   }
   return result;
 } /* ------------------------------------------------------ */

 void far pc_textmode (void)
 /* SPECIFIC TO MS-DOS */
 /* Restore text mode */
 /* Automatically called on pgm termination */
 {
 union REGS r;

   if (oldmode) {              /* if not in text mode now... */
     r.h.ah = 0;
     r.h.al = oldmode;                  /* restore text mode */
     int86 (0x10, &r, &r);
     movedata                         /* restore text screen */
         (FP_SEG (vidsave), FP_OFF (vidsave), vidmem, 0, 4096);
     free (vidsave);                /* free allocated memory */
     vidsave = 0;                            /* zero pointer */
     oldmode = 0;                                   /* reset */
     r.h.ah = 2;              /* restore old cursor position */
     r.h.bh = textpage;
     r.x.dx = curpos;
     int86 (0x10, &r, &r);
   }
 } /* ------------------------------------------------------ */

 void far set_color1 (int palette_reg)
 /* Select pixel color from palette register */
 {
   color1 = palette_reg;
 } /* ------------------------------------------------------ */


<a name="0076_000c"><a name="0076_000c">
<a name="0076_000d">
[LISTING THREE]
<a name="0076_000d">

/* Library source file GRAFIX.C               */
/* EGA/VGA graphics subsystem                 */
/* Following library routines are external:   */
/*     DRAWPT.ASM       Feb '89               */
/* K. Porter, DDJ Graphics Programming Column */
/* ------------------------------------------ */

#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "grafix.h"

#if !defined TRUE
#define FALSE 0
#define TRUE  !FALSE
#endif

/* Variables global to this library */
int  color1,                            /* foreground color */
     oldmode = 0,                      /* pre-graphics mode */
     grafixmode = 0,               /* default graphics mode */
     ega = FALSE,                     /* equipment Booleans */
     vga = FALSE,
     colormonitor = FALSE,
     curpos,                        /* text cursor position */
     textpage;                          /* active text page */
unsigned vidmem;                    /* video buffer segment */
char far *vidsave;                /* video buffer save area */

/* -------------------------------------------------------- */

int far init_video (int mode)

/* Initializes video adapter and defaults for mode          */
/* Sets up pc_textmode() to be called on pgm termination    */
/* Returns TRUE or FALSE indicating success                 */
/* This function will be expanded in a later version        */
{
union REGS r;
int result = FALSE;

  /* Determine attached adapter and monitor */
  r.h.ah = 0x1A;                    /* VGA inquiry function */
  r.h.al = 0;
  int86 (0x10, &r, &r);                    /* ROM BIOS call */
  if (r.h.al == 0x1A)
    switch (r.h.bl) {
      case 4 : ega = TRUE;                     /* EGA color */
               colormonitor = TRUE;
               break;
      case 5 : ega = TRUE;                      /* EGA mono */
               break;
      case 7 : ega = TRUE;                      /* VGA mono */
               vga = TRUE;
               break;
      case 8 : ega = TRUE;                     /* VGA color */
               vga = TRUE;
               colormonitor = TRUE;
    }
  else {                        /* No VGA, so check for EGA */
    r.h.ah = 0x12;
    r.x.bx = 0x10;
    int86 (0x10, &r, &r);
    if (r.x.bx != 0x10) {              /* if EGA present... */
      ega = TRUE;                               /* set flag */
      r.h.ah = 0x12;
      r.h.bl = 0x10;              /* find out which monitor */
      int86 (0x10, &r, &r);
      if (r.h.bh == 0)
        colormonitor = TRUE;                   /* EGA color */
    }
  }

  /* Proceed only if EGA or VGA present */
  if (ega | vga) {
    set_color1 (15);                 /* default pixel color */

    r.h.ah = 0x0F;               /* get current screen mode */
    int86 (0x10, &r, &r);
    oldmode = r.h.al;                           /* store it */
    textpage = r.h.bh;             /* also active text page */

    if (colormonitor)              /* point to video memory */
      vidmem = 0xB800;
    else
      vidmem = 0xB000;

    vidsave = malloc (4096);          /* allocate save area */
    movedata                   /* save text screen contents */
        (vidmem, 0, FP_SEG (vidsave), FP_OFF (vidsave), 4096);

    r.h.ah = 3;                 /* get text cursor position */
    r.h.bh = textpage;
    int86 (0x10, &r, &r);
    curpos = r.x.dx;                         /* and save it */

    if ((mode == EGA) && ega) {
      r.h.ah = 0;
      r.h.al = mode;                        /* set EGA mode */
      int86 (0x10, &r, &r);
      result = TRUE;
    } else
      if ((mode == vga) && vga) {
        r.h.ah = 0;
        r.h.al = mode;
        int86 (0x10, &r, &r);
        result = TRUE;
      }
  }
  if (!result) {            /* unable to switch to graphics */
    oldmode = 0;              /* so cancel text screen save */
    free (vidsave);
    vidsave = 0;
  } else {                             /* successful, so... */
    grafixmode = mode;                         /* save mode */
    atexit (pc_textmode);         /* register exit function */
  }
  return result;
} /* ------------------------------------------------------ */

void far pc_textmode (void)
/* SPECIFIC TO MS-DOS */
/* Restore text mode */
/* Automatically called on pgm termination */
{
union REGS r;

  if (oldmode) {              /* if not in text mode now... */
    r.h.ah = 0;
    r.h.al = oldmode;                  /* restore text mode */
    int86 (0x10, &r, &r);
    movedata                         /* restore text screen */
        (FP_SEG (vidsave), FP_OFF (vidsave), vidmem, 0, 4096);
    free (vidsave);                /* free allocated memory */
    vidsave = 0;                            /* zero pointer */
    oldmode = 0;                                   /* reset */
    r.h.ah = 2;              /* restore old cursor position */
    r.h.bh = textpage;
    r.x.dx = curpos;
    int86 (0x10, &r, &r);
  }
} /* ------------------------------------------------------ */

void far set_color1 (int palette_reg)
/* Select pixel color from palette register */
{
  color1 = palette_reg;
} /* ------------------------------------------------------ */


<a name="0076_000e"><a name="0076_000e">
<a name="0076_000f">
[LISTING FOUR]
<a name="0076_000f">

/* STRIPES.C: Demos pixel-writing with GRAFIX library */

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "grafix.h"

void main ()
{
int  x, y, color;

  if (!init_video (EGA)) {
    puts ("No EGA/VGA present in system: Program ended");
    exit (1);
  } else {
    for (y = 95; y < 255; y++) {
      color = y % 16;                 /* first color this row */
      for (x = 160; x < 480; x++) {
        set_color1 (color);           /* set color this pixel */
        draw_point (x, y);
        if (++color == 16) color = 0;  /* wrap around palette */
      }
    }
    getch();                             /* hold for keypress */
  }
}









Copyright © 1989, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.