home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_06_06 / v6n6044a.txt < prev    next >
Text File  |  1989-09-28  |  12KB  |  341 lines

  1.  \NLETTER\6.6\TRIANGLE.C/*
  2. Copyright (C) Magna Carta Software, 1988.  All Rights Reserved.
  3.  
  4.  
  5. Scroll and pan a graphics image on the screen in video mode 0X10 (640x350
  6. 16-color graphics).  Note: This program assumes the presence of an EGA
  7. driving an Enhanced Color Display or a VGA.  Furthermore, that this adapter
  8. is active.  Simple invocataion syntax:
  9. TURBO C:        tcc sgraph
  10. MSC v5.0+:      cl /DMSC sgraph.c
  11. POWER C v1.1+   pc /e sgraph
  12. WATCOM C v6.0+  wcc sgraph -ms
  13.                 wlink FILE sgraph LIB ?:\watcomc\lib\clibs, ?:\watcomc\lib\maths
  14.                 OPTION Map, caseexact, stack=2048
  15. First version: 5/7/88.  Last revised: 6/1/88.
  16. */
  17.  
  18.  
  19. #include <conio.h>
  20. #include <dos.h>
  21. #include <stdio.h>
  22.  
  23.  
  24. typedef unsigned char BYTE;
  25.  
  26. /* COMPILER SPECIFIC DETAILS */
  27. #if defined(MSC) || defined(__WATCOMC__)
  28.     #define inportb(port) inp(port)
  29.     #define outportb(port,value) outp((port),(value))
  30.     #define outport(port,value) outpw((port),(value))
  31. #endif
  32.  
  33. /* MANIFEST CONSTANTS */
  34. #define FALSE           0
  35. #define TRUE            !FALSE
  36. #define LOGICAL_WIDTH   132         /* logical screen width in bytes        */
  37. #define VIDEO           0X10        /* BIOS interrupt 0X10 -- video         */
  38. #define YELLOW          14          /* the color for the graphics image     */
  39.  
  40. /* EGA and VGA register values */
  41. #define START_ADDRESS_HIGH  0X0C  /* Address of start address h reg. of CRTC */
  42. #define START_ADDRESS_LOW   0X0D  /* Address of start address l reg. of CRTC */
  43. #define AC_INDEX            0X3C0 /* Attribute Controller Index Register     */
  44. #define AC_HPP              0X13 | 0X20 /* Horizontal Pel Panning Register   */
  45.                                         /* Note: ORed with 20H to preserve   */
  46.                                         /* bit 5                             */
  47. #define OFFSET_REG            0X013
  48.  
  49. /* GLOBAL VARIABLES */
  50. unsigned right_edge, left_edge; /* TRUE if we are at the edge of the screen */
  51. int vpel, hpel;
  52. int mono = FALSE;               /* EGA monochrome */
  53.  
  54.  
  55. struct video_descriptor {
  56.     BYTE far *base;             /* starting address of the video buffer     */
  57.     unsigned isr;               /* EGA/VGA input status register address    */
  58.     unsigned crtc;              /* CRT Controller Register address          */
  59. };
  60.  
  61.  
  62. struct screen_descriptor {
  63.     unsigned rows;
  64.     unsigned cols;
  65.     unsigned logical_width;     /* screen logical width in words. max: 0X100 */
  66.     unsigned start_addr;        /* screen start address. max: 0X4000         */
  67. };
  68.  
  69.  
  70. struct video_descriptor video;
  71. struct screen_descriptor screen;
  72.  
  73. /* FUNCTION PROTOTYPES */
  74. int fill_triag(int color, int v[][2]);
  75. void scanline(unsigned x0, unsigned x1, unsigned y, int color);
  76. unsigned smooth_scroll(int count, unsigned speed);
  77. unsigned smooth_pan(int count, unsigned speed);
  78. unsigned set_logical_screen_width(unsigned l_width);
  79. void set_start_addr(unsigned start_addr);
  80. void set_pel_pan(int hpel);
  81.  
  82.  
  83. void main(void)
  84. {
  85.     union REGS regs;
  86.                         /* top ----- left corner - right corner */
  87.     static int v1[][2] = {{100, 25}, {50, 125}, {150, 125}};
  88.  
  89.     /* ESTABLISH THE SYSTEM STATUS */
  90.  
  91.     /* initialize the base address of the video buffer */
  92.     video.base          = (BYTE far *) 0XA0000000L;
  93.     screen.start_addr   = 0;            /* initialize the start address */
  94.  
  95.     regs.x.ax = 0X0010;                 /* set video mode to 10 hex. */
  96.     int86(0X10, ®s, ®s);
  97.  
  98.     /* initialize the logical screen width in bytes */
  99.     screen.logical_width = LOGICAL_WIDTH;
  100.     screen.cols = screen.logical_width;
  101.  
  102.     video.isr   = 0X03da;           /* address of input status register     */
  103.     video.crtc  = video.isr - 6;    /* address of CRT controller register   */
  104.  
  105.     /* SET THE LOGICAL SCREEN WIDTH FOR PANNING AND THE START ADDRESS */
  106.     set_logical_screen_width(screen.logical_width);
  107.     set_start_addr(screen.start_addr);
  108.  
  109.     /* WE MUST DO A DUMMY READ OF THE INPUT STATUS REGISTER TO INITIALIZE
  110.     THE TOGGLE OF THE ATTRIBUTE CONTROLLER (see text of article )           */
  111.     inportb(video.isr);
  112.  
  113.     fill_triag(YELLOW, v1); /* draw the graphic image on the screen             */
  114.  
  115.     /* ALL THE SCROLLING-PANNING ACTION IS HANDLED HERE */
  116.     do {
  117.         smooth_scroll(-100,2);
  118.         smooth_pan(-300,1);
  119.         smooth_scroll(100,2);
  120.         smooth_pan(300,1);
  121.     } while (!kbhit());
  122.  
  123.     /* A KEY WAS HIT -- RETURN TO 80 COLUMN COLOR TEXT MODE AND EXIT */
  124.     getch();
  125.     regs.x.ax = 0X0003;
  126.     int86(0X10, ®s, ®s);
  127. }
  128.  
  129.  
  130. /* Fill an isosceles triangle with one side contiguous with a scan line and
  131. an apex at the top.
  132. */
  133.  
  134. int fill_triag(int color, int v[][2])
  135. {
  136.     int y, start, end;
  137.     double left_slope, right_slope, x0, x1, x2, y0, y1, y2;
  138.  
  139.     x0 = v[0][0];
  140.     x1 = v[1][0];
  141.     x2 = v[2][0];
  142.     y0 = v[0][1];
  143.     y1 = v[1][1];
  144.     y2 = v[2][1];
  145.  
  146.     left_slope  = (x1 - x0)/(y1 - y0);      /* Compute slopes           */
  147.     right_slope = (x2 - x0)/(y2 - y0);      /* Compute slopes           */
  148.     for (y = y0; y <= y1; y++) {        /* Loop over raster lines   */
  149.         start = x0 + (y - y0)*left_slope;
  150.         end   = x0 + (y - y0)*right_slope;
  151.         scanline(start,end,y,color);    /* Fill next section    */
  152.     }
  153.  
  154.     return (0);
  155. }
  156.  
  157.  
  158. void scanline(unsigned start, unsigned stop, unsigned raster, int color)
  159. {
  160. #define GRAPHICSC   0X03CE
  161. #define SEQUENCER   0X03C4
  162. #define BIT_MASK    8
  163.  
  164.     unsigned i, mask;
  165.     BYTE oddbits, byte, far *s_offset;
  166.     int scan_len;
  167.  
  168.     scan_len = stop - start;        /* length -1 in pixels */
  169.  
  170. /* --- Load SET/RESET registers with current color                          */
  171.  
  172.     outport(GRAPHICSC, color << 8); /* move color into reset register       */
  173.     outport(GRAPHICSC, 0X0F01);     /* enable use of reset register         */
  174.     outport(SEQUENCER, 0X0F02);     /* enable all planes for write          */
  175.  
  176. /* ----------- COMPUTE ADDRESS AND MASK FOR FIRST PIXEL -------------       */
  177.     s_offset = video.base + screen.logical_width*raster + (start >> 3);
  178.     if ( (oddbits = start & 7) != 0) {
  179.         mask = 0X00FF >> oddbits;
  180.         scan_len += oddbits;
  181.         scan_len -= 8;
  182.         if (scan_len < 0) {
  183.             scan_len = (~scan_len) + 1;
  184.             mask = mask >> (BYTE) scan_len;
  185.             mask = mask << (BYTE) scan_len;
  186.             scan_len = 0;
  187.     }
  188.         outport(GRAPHICSC, (mask << 8) | BIT_MASK); /* unmask bit mask */
  189.         byte = *s_offset;                 /* latch data */
  190.         *s_offset++ = byte;               /* write data */
  191.     }
  192.  
  193. /* ---------------- WRITE COMPLETE BYTES --------------------       */
  194.     if (scan_len >= 8) {
  195.         outport(GRAPHICSC, (0XFFFF << 8) | BIT_MASK);   /* unmask bit mask */
  196.         for (i=0; i < (scan_len >> 3); i++) *s_offset++ = byte;
  197.     }
  198.  
  199. /* --- COMPUTE ADDRESS AND MASK FOR LAST PIXEL -------------        */
  200.  
  201.     if ( (oddbits = scan_len & 7) != 0) {
  202.         mask = (0XFF >> oddbits) ^ 0XFF;
  203.         outport(GRAPHICSC, (mask << 8) | BIT_MASK);
  204.         byte = *s_offset;                 /* latch data */
  205.         *s_offset++ = byte;               /* write data */
  206.     }
  207.  
  208.  
  209. /* RESTORE BIT MASK AND SET/RESET REGISTERS */
  210.     outport(GRAPHICSC, (0XFFFF << 8) | BIT_MASK);
  211.     outport(GRAPHICSC, 0X0001);
  212. }
  213.  
  214.  
  215.  
  216. /* SMOOTH_SCROLL scrolls the EGA video buffer the number of scan lines
  217. indicated in "count" at a speed of "speed" scan lines per vertical retrace.
  218. */
  219. unsigned smooth_scroll(int count, unsigned speed)
  220. {
  221.  
  222.     unsigned i, max_count;
  223.  
  224.     max_count = (count < 0) ? -count : count;
  225.  
  226.     /* GET THE START ADDRESS OF THE SCREEN BUFFER */
  227.     outportb(video.crtc, START_ADDRESS_HIGH);       /* High byte */
  228.     screen.start_addr = inportb(video.crtc+1) << 8;
  229.     outportb(video.crtc, START_ADDRESS_LOW);        /* Low byte */
  230.     screen.start_addr |= inportb(video.crtc+1);
  231.  
  232.     /* COUNT > 0 => SCROLL SCREEN IMAGE UPWARDS. */
  233.     for(i=0;i < max_count; i+=speed) {
  234.         screen.start_addr = (count > 0) ?
  235.             screen.start_addr + screen.logical_width*speed :
  236.             screen.start_addr - screen.logical_width*speed;
  237.         /* wait for the end of a vertical retrace */
  238.         while (inportb(video.isr) & 8);
  239.         /* wait for the next vertical retrace */
  240.         while (!(inportb(video.isr) & 8));
  241.         set_start_addr(screen.start_addr);
  242.     }
  243.     return (screen.start_addr);
  244. }
  245.  
  246.  
  247. /* SMOOTH_PAN
  248. This function invokes smooth panning on the EGA/VGA.  The function calculates
  249. the number of scan lines per row.  The speed variable adjusts the speed in
  250. pixels per vertical retrace and takes values in the range 1-8.
  251. */
  252. unsigned smooth_pan(int count, unsigned speed)
  253. {
  254.     unsigned i;
  255.  
  256.     /* count greater than zero (move viewport to the right) */
  257.     if (count>0 && !right_edge) for(i=0;i<count;) {
  258.  
  259.         /* if we have scrolled a full character, reset start address */
  260.         if (hpel>=8) {
  261.             screen.start_addr++;
  262.             left_edge = FALSE;
  263.             if (!(screen.start_addr % (screen.logical_width))) right_edge = TRUE;
  264.             if (!right_edge) hpel %= 8;    /* reset the pel counter */
  265.             else {
  266.                 hpel = 0;
  267.                 i = count - 1;
  268.             }
  269.             set_start_addr(screen.start_addr);
  270.         }
  271.         for(;hpel < 8 && i < count;i+=speed, hpel+=speed) set_pel_pan(hpel);
  272.     }
  273.  
  274.     /* count less than zero (move viewport to the left) */
  275.     else if (count<0) {
  276.         if (hpel>7) hpel = hpel - 8;
  277.         for(i=0;i<(-count) ;) {
  278.             /* if we have scrolled a full character, reset start address */
  279.             if (hpel<0 && !left_edge) {
  280.                 screen.start_addr--;
  281.                 right_edge = FALSE;
  282.                 if (!(screen.start_addr % (screen.logical_width))) left_edge = TRUE;
  283.                 hpel = 8 + hpel;
  284.                 set_start_addr(screen.start_addr);
  285.             }
  286.             else if (hpel<0 && left_edge) i = (-count);
  287.             for(;hpel >= 0 && i < (-count);i+=speed, hpel-=speed) set_pel_pan(hpel);
  288.         }
  289.     }
  290.     return (screen.start_addr);
  291. }
  292.  
  293.  
  294. /* SET_LOGICAL_SCREEN_WIDTH defines an EGA/VGA screen width for smooth panning
  295. and sets the the global variable "screen.cols."  screen.cols must be restored
  296. when smooth panning is finished or subsequent screen writes will address the
  297. wrong screen locations.
  298. l_width is the width of the logical screen in bytes. Max 512.
  299. */
  300. unsigned set_logical_screen_width(unsigned l_width)
  301. {
  302.     l_width = (l_width > 512) ? 512 : l_width;
  303.  
  304.     /* set screen_cols */
  305.     screen.cols = l_width;
  306.  
  307.     /* set logical screen width */
  308.     l_width >>= 1;                                  /* convert to words */
  309.     outport(video.crtc, (l_width << 8) | OFFSET_REG);
  310.  
  311.     return (l_width << 1);
  312. }
  313.  
  314.  
  315. /* SET_START_ADDRESS -- Sets the start address of the screen. I.e. the  */
  316. /* address that occupies the top left of the screen.                    */
  317. void set_start_addr(unsigned start_addr)
  318. {
  319.     /* address the start address high register */
  320.     outport(video.crtc, (start_addr & 0XFF00) | START_ADDRESS_HIGH);
  321.  
  322.     /* address the start address low register */
  323.     outport(video.crtc, (start_addr << 8) | START_ADDRESS_LOW);
  324. }
  325.  
  326.  
  327. /* SET_PEL_PAN -- Sets the horizontal pel panning register to the value     */
  328. /* specified in "hpel".  Called by smooth_pan()                             */
  329. void set_pel_pan(int hpel)
  330. {
  331.     /* first wait for end of vertical retrace */
  332.     while (inportb(video.isr) & 8);
  333.  
  334.     /* wait for next vertical retrace */
  335.     while (!(inportb(video.isr) & 8));
  336.  
  337.     /* address the horizontal pel paning register */
  338.     outportb(AC_INDEX, AC_HPP);
  339.     outportb(AC_INDEX, hpel);
  340. }
  341.