home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n05 / graphprg.asc < prev    next >
Encoding:
Text File  |  1992-03-30  |  11.1 KB  |  282 lines

  1. _GRAPHICS PROGRAMMING COLUMN_
  2. by Michael Abrash
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* Utility to force an ET4000-based VGA into 16- or 8-bit operation even if 
  8. a monochrome adapter is in the system. (Note that only 16-bit memory access, 
  9. not 16-bit I/O, is enabled; the I/O state is not altered.) The monochrome 
  10. adapter won't work properly while SETBUS 16 is in effect. Tested with 
  11. Borland C++ 3.0. Courtesy of Charles Marslett of STB. Commented and 
  12. reformatted by Michael Abrash. */
  13.  
  14. /*****************************************************************************
  15.  * This utility isn't known to cause problems, but use it at your own risk, as 
  16.  * the monochrome and VGA adapters will both respond to accesses to monochrome 
  17.  * display memory while SETBUS 16 is in effect, resulting in bus contention. 
  18.  ****************************************************************************/
  19. #include <dos.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. void main(int argc, char *argv[])
  24. {
  25.    int crtc, val;
  26.    union REGS regset;
  27.  
  28.    if (inp(0x3CC) & 0x01)  /* decide where to address the CRT */
  29.       crtc = 0x3D4;        /* Controller by reading the I/O */
  30.    else                    /* Address Select bit of the */
  31.       crtc = 0x3B4;        /* Miscellaneous Output register */
  32.  
  33.    outportb(0x3BF, 0x03);  /* key sequence to enable access to */
  34.    outportb(crtc+4, 0xA0); /* ET4000-specific registers */
  35.    outportb(crtc, 0x36);   /* get the current setting of the Video */
  36.    val = inp(crtc+1);      /* System Configuration 1 register */
  37.  
  38.    /* Decide whether 16- or 8-bit access desired, and configure accordingly */
  39.    if (argc == 2) {
  40.       if (strcmp(argv[1], "16") == 0) {
  41.          outportb(crtc+1, val | 0x40);  /* 16-bit memory access */
  42.          goto ModeSet;
  43.       } else if (strcmp(argv[1], "8") == 0) {
  44.          outportb(crtc+1, val & 0xBF);  /* 8-bit memory access */
  45. ModeSet:
  46.          regset.x.ax = 0x0003;
  47.          int86(0x10, ®set, ®set); /* do a text mode mode set */
  48.          exit(0);
  49.       }
  50.    }
  51.    fprintf(stderr, "Usage: SETBUS 16\n");
  52.    fprintf(stderr, "   or  SETBUS 8\n");
  53.    exit(1);
  54. }
  55.  
  56.  
  57.  
  58. [LISTING TWO]
  59.  
  60. /* Function to tell the BIOS to set up properly sized characters for 25 rows of
  61.  16 pixel high text in 640x400 graphics mode. Call immediately after mode set. 
  62.  Based on a contribution by Bill Lindley. */
  63.  
  64. #include <dos.h>
  65.  
  66. void Set640x400()
  67. {
  68.    union REGS regs;
  69.  
  70.    regs.h.ah = 0x11; /* character generator function */
  71.    regs.h.al = 0x24; /* use ROM 8x16 character set for graphics */
  72.    regs.h.bl = 2;    /* 25 rows */
  73.    int86(0x10, ®s, ®s); /* invoke the BIOS video interrupt
  74.                                  to set up the text */
  75. }
  76.  
  77.  
  78.  
  79. [LISTING THREE]
  80.  
  81.  
  82. /* Draws the 8x8 monochrome icon pointed to by IconPtr at coordinates (X,Y) in
  83.  the DestWidth-wide bitmap starting at DestSeg:0, using the transparent 
  84.  replace raster op and color Color. Destination bitmap must be an 
  85.  8-bit-per-pixel bitmap. 1-bits in the pattern are converted to drawing color 
  86.  and drawn, and 0-bits are skipped over, preserving destination (that is, are 
  87.  transparent). Tested with Borland C++ 3.0; when USE_C is 0, uses 
  88.  BC++ dependent inline assembly. */
  89.  
  90. #define USE_C  0  /* set to 1 to compile C code, 0 to compile assembler */
  91. #if !USE_C
  92. #pragma inline /* tell the compiler there's inline ASM code */
  93. #else
  94. #include <dos.h>
  95. #endif
  96.  
  97. void DrawReplaceXpar(unsigned int X, unsigned int Y,
  98.    unsigned int DestSeg, unsigned int DestWidth,
  99.    unsigned int Color, unsigned char *IconPtr)
  100. {
  101. #if USE_C
  102.    unsigned char far *ScreenPtr, Temp;
  103.    int i,j;
  104.  
  105.    /* Point to the first destination pixel */
  106.    ScreenPtr = MK_FP(DestSeg, Y*DestWidth+X);
  107.    for (i=0; i<8; i++) {   /* do the 8 icon rows */
  108.       Temp = *IconPtr++;   /* get the next icon row */
  109.       for (j=0; j<8; j++) { /* do the 8 pixels per icon row */
  110.          if (Temp & 0x80)        /* draw this pixel if the */
  111.             *ScreenPtr = Color;  /* corresponding icon bit is 1 */
  112.          ScreenPtr++;      /* point to the next destination pixel */
  113.          Temp <<= 1;       /* shift the next icon bit into place */
  114.       }
  115.        /* Point to the start of the next row */
  116.       ScreenPtr += DestWidth - 8;
  117.    }
  118. #else
  119.    asm   cld               /* make LODSB increment SI */
  120.    asm   mov   es,DestSeg  /* point ES to the bitmap */
  121.    asm   mov   ax,Y
  122.    asm   mov   bx,DestWidth
  123.    asm   mul   bx          /* DestWidth*Y+X = offset of first */
  124.    asm   add   ax,X        /*  dest pixel */
  125.    asm   mov   di,ax       /* point ES:DI to the first dest pixel */
  126.    asm   mov   si,IconPtr  /* point DS:SI to the first icon byte */
  127.    asm   mov   dx,8        /* we'll do 8 rows */
  128.    asm   mov   ah,byte ptr Color /* color we'll draw with */
  129.    asm   sub   bx,8      /* offset from end of one dest row to start of next */
  130. RowLoop:
  131.    asm   lodsb             /* get the next icon row */
  132.    asm   mov   cx,8        /* we'll do 8 pixels on each row */
  133. PixelLoop:
  134.    asm   shl   al,1        /* shift the next icon bit into CF */
  135.    asm   jnc   NoDraw      /* bit is 0, so don't draw */
  136.    asm   mov   es:[di],ah  /* bit is 1, so draw this pixel */
  137. NoDraw:
  138.    asm   inc   di          /* point to the next destination pixel */
  139.    asm   loop  PixelLoop   /* do the next pixel */
  140.    asm   add   di,bx       /* point to the start of the next dest row */
  141.    asm   dec   dx          /* count down rows */
  142.    asm   jnz   RowLoop     /* do the next row */
  143. #endif
  144. }
  145.  
  146.  
  147. [LISTING FOUR]
  148.  
  149. /* Compiled bitblit code for drawing the 8x8 monochrome icon pointed to by 
  150. IconPtr at coordinates (X,Y) in the DestWidth-wide bitmap starting at 
  151. DestSeg:0, using the transparent replace raster op and color Color. 
  152. CompileReplaceXpar() generates code to perform desired bitblit, and 
  153. ExecuteCompiled() executes that code to perform bitblit. Generally faster than 
  154. a standard approach when drawing the same icon many times, because this way
  155. color expansion, transparency, and reading the source are only performed once, 
  156. at expansion time, rather than every time an icon is drawn. Destination bitmap 
  157. must be an 8-bit-per-pixel bitmap. 1-bits in pattern are converted to drawing 
  158. color and drawn, and 0-bits are skipped over, preserving destination (that is, 
  159. are transparent). Tested with Borland C++ 3.0; uses BC++ dependent inline 
  160. assembly. */
  161.  
  162. #pragma inline /* tell the compiler there's inline ASM code */
  163.  
  164. /* Generates far-callable code to bitblit the specified icon, and stores code 
  165. in BufferToCompileInto. Code is simply a series of MOV [DI+xxxx],AL 
  166. instructions, where xxxx is the offset from upper left corner of icon of 
  167. each pixel to be drawn. */
  168. void CompileReplaceXpar(unsigned int DestWidth,
  169.    unsigned char *IconPtr, unsigned char *BufferToCompileInto)
  170. {
  171.    unsigned int i, j, PixelOffset = 0;
  172.    unsigned char Temp;
  173.  
  174.    for (i=0; i<8; i++) {   /* do the 8 icon rows */
  175.       Temp = *IconPtr++;   /* get the next icon row */
  176.       for (j=0; j<8; j++) { /* do the 8 pixels per icon row */
  177.          if (Temp & 0x80) { /* generate the code to draw this pixel if the 
  178.                             corresponding icon bit is 1. Code is the hex bytes 
  179.                             for the instruction MOV [DI+PixelOffset],AL */
  180.             *BufferToCompileInto++ = 0x88;  /* MOV opcode */
  181.             *BufferToCompileInto++ = 0x85;  /* mod-reg-rm byte */
  182.             *((unsigned int *)BufferToCompileInto)++ = PixelOffset;
  183.                                     /* addressing displacement */
  184.          }
  185.          PixelOffset++;    /* point to the next destination pixel */
  186.          Temp <<= 1;       /* shift the next icon bit into place */
  187.       }
  188.        /* Point to the start of the next row in the destination */
  189.       PixelOffset += DestWidth - 8;
  190.    }
  191.    /* Put a RET at the end to return to the calling code, and done */
  192.    *BufferToCompileInto = 0xCB;  /* RETF instruction = 0xCB */
  193. }
  194. void ExecuteCompiled(unsigned int X, unsigned int Y,
  195.    unsigned int DestSeg, unsigned int DestWidth, unsigned int Color,
  196.    unsigned char far *BufferToExecute)
  197. {
  198.    asm   push  ds          /* preserve the default data segment */
  199.    asm   mov   ds,DestSeg  /* point ES to the bitmap */
  200.    asm   mov   ax,Y
  201.    asm   mul   word ptr DestWidth /* DestWidth*Y+X = offset of */
  202.    asm   add   ax,X               /*  first dest pixel */
  203.    asm   mov   di,ax       /* point ES:DI to the first dest pixel */
  204.    asm   mov   al,Color    /* color with which to draw */
  205.    asm   call  dword ptr BufferToExecute
  206.                            /* perform a far call to execute the
  207.                               compiled bitblit code, and done */
  208.    asm   pop   ds          /* restore the default data segment */
  209. }
  210.  
  211.  
  212.  
  213. [LISTING FIVE]
  214.  
  215. /* Sample program to tile screen with an 8x8 monochrome icon.
  216. Tested with Borland C++ 3.0. */
  217.  
  218. #include <dos.h>
  219. #include <conio.h>
  220.  
  221. #define USE_COMPILED_BITBLITS 1 /* set to 1 and link to Listing 4 to use 
  222.                                 compiled biblits, set to 0 and link to 
  223.                                 Listing 3 to use conventional bitblits */
  224. #define SCREEN_WIDTH    320
  225. #define SCREEN_HEIGHT   200
  226. #define SCREEN_SEGMENT  0xa000
  227.  
  228. #if USE_COMPILED_BITBLITS
  229. extern void CompileReplaceXpar(unsigned int, unsigned char *, unsigned char *);
  230. extern void ExecuteCompiled(unsigned int, unsigned int, unsigned int,
  231.    unsigned int, unsigned int, unsigned char far *);
  232. #else
  233. extern void DrawReplaceXpar(unsigned int, unsigned int,
  234.    unsigned int, unsigned int, unsigned int, unsigned char *);
  235. #endif
  236.  
  237. static unsigned char TestIcon[8] = 
  238.    {0x88, 0x44, 0x22, 0x11, 0x11, 0x22, 0x44, 0x88};
  239. #if USE_COMPILED_BITBLITS
  240. /* Storage for the compiled icon-drawing code; must be large enough for the 
  241. largest possible code size, because no error checking is performed */
  242. static unsigned char CompiledBuffer[1000];
  243. #endif
  244.  
  245. void main()
  246. {
  247.    unsigned int x, y;
  248.    union REGS regset;
  249. #if USE_COMPILED_BITBLITS
  250.    unsigned char far *CompiledBufferPtr;
  251. #endif
  252.    regset.x.ax = 0x0013;            /* AL = 0x13 selects 320x200 */
  253.    int86(0x10, ®set, ®set);   /*  256-color graphics mode */
  254. #if USE_COMPILED_BITBLITS
  255.    /* Generate the code for drawing the icon with the transparent
  256.       replace raster op, and store the code in CompiledBuffer */
  257.    CompileReplaceXpar(SCREEN_WIDTH, TestIcon, CompiledBuffer);
  258.    CompiledBufferPtr = MK_FP(_DS, CompiledBuffer);
  259. #endif
  260.    /* Tile TestIcon over the entire screen */
  261.    for (y=0; y<SCREEN_HEIGHT; y += 8) {
  262.       for (x=0; x<SCREEN_WIDTH; x += 8) {
  263. #if USE_COMPILED_BITBLITS
  264.          /* Draw the icon by executing the code in CompiledBuffer */
  265.          ExecuteCompiled(x, y, SCREEN_SEGMENT, SCREEN_WIDTH, 14,
  266.                CompiledBufferPtr);
  267. #else
  268.          /* Draw the icon with the transparent replace raster op, color 
  269.             expanding it and handling transparency on the fly */
  270.          DrawReplaceXpar(x, y, SCREEN_SEGMENT, SCREEN_WIDTH, 14,TestIcon);
  271. #endif
  272.       }
  273.    }
  274.    getch();                /* wait for a key press */
  275.    regset.x.ax = 0x0003;   /* AL = 3 selects 80x25 text mode */
  276.    int86(0x10, ®set, ®set);   /* return to text mode */
  277.    exit(1);                /* done */
  278. }
  279.  
  280.  
  281.  
  282.