home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (C) Magna Carta Software, 1988. All Rights Reserved.
-
-
- Scroll and pan a graphics image on the screen in video mode 0X10 (640x350
- 16-color graphics). Note: This program assumes the presence of an EGA
- driving an Enhanced Color Display or a VGA. Furthermore, that this adapter
- is active. Simple invocataion syntax:
- TURBO C: tcc sgraph
- MSC v5.0+: cl /DMSC sgraph.c
- POWER C v1.1+ pc /e sgraph
- WATCOM C v6.0+ wcc sgraph -ms
- wlink FILE sgraph LIB ?:\watcomc\lib\clibs, ?:\watcomc\lib\maths
- OPTION Map, caseexact, stack=2048
- First version: 5/7/88. Last revised: 6/1/88.
- */
-
-
- #include <conio.h>
- #include <dos.h>
- #include <stdio.h>
-
-
- typedef unsigned char BYTE;
-
- /* COMPILER SPECIFIC DETAILS */
- #if defined(MSC) || defined(__WATCOMC__)
- #define inportb(port) inp(port)
- #define outportb(port,value) outp((port),(value))
- #define outport(port,value) outpw((port),(value))
- #endif
-
- /* MANIFEST CONSTANTS */
- #define FALSE 0
- #define TRUE !FALSE
- #define LOGICAL_WIDTH 132 /* logical screen width in bytes */
- #define VIDEO 0X10 /* BIOS interrupt 0X10 -- video */
- #define YELLOW 14 /* the color for the graphics image */
-
- /* EGA and VGA register values */
- #define START_ADDRESS_HIGH 0X0C /* Address of start address h reg. of CRTC */
- #define START_ADDRESS_LOW 0X0D /* Address of start address l reg. of CRTC */
- #define AC_INDEX 0X3C0 /* Attribute Controller Index Register */
- #define AC_HPP 0X13 | 0X20 /* Horizontal Pel Panning Register */
- /* Note: ORed with 20H to preserve */
- /* bit 5 */
- #define OFFSET_REG 0X013
-
- /* GLOBAL VARIABLES */
- unsigned right_edge, left_edge; /* TRUE if we are at the edge of the screen */
- int vpel, hpel;
- int mono = FALSE; /* EGA monochrome */
-
-
- struct video_descriptor {
- BYTE far *base; /* starting address of the video buffer */
- unsigned isr; /* EGA/VGA input status register address */
- unsigned crtc; /* CRT Controller Register address */
- };
-
-
- struct screen_descriptor {
- unsigned rows;
- unsigned cols;
- unsigned logical_width; /* screen logical width in words. max: 0X100 */
- unsigned start_addr; /* screen start address. max: 0X4000 */
- };
-
-
- struct video_descriptor video;
- struct screen_descriptor screen;
-
- /* FUNCTION PROTOTYPES */
- int fill_triag(int color, int v[][2]);
- void scanline(unsigned x0, unsigned x1, unsigned y, int color);
- unsigned smooth_scroll(int count, unsigned speed);
- unsigned smooth_pan(int count, unsigned speed);
- unsigned set_logical_screen_width(unsigned l_width);
- void set_start_addr(unsigned start_addr);
- void set_pel_pan(int hpel);
-
-
- void main(void)
- {
- union REGS regs;
- /* top ----- left corner - right corner */
- static int v1[][2] = {{100, 25}, {50, 125}, {150, 125}};
-
- /* ESTABLISH THE SYSTEM STATUS */
-
- /* initialize the base address of the video buffer */
- video.base = (BYTE far *) 0XA0000000L;
- screen.start_addr = 0; /* initialize the start address */
-
- regs.x.ax = 0X0010; /* set video mode to 10 hex. */
- int86(0X10, ®s, ®s);
-
- /* initialize the logical screen width in bytes */
- screen.logical_width = LOGICAL_WIDTH;
- screen.cols = screen.logical_width;
-
- video.isr = 0X03da; /* address of input status register */
- video.crtc = video.isr - 6; /* address of CRT controller register */
-
- /* SET THE LOGICAL SCREEN WIDTH FOR PANNING AND THE START ADDRESS */
- set_logical_screen_width(screen.logical_width);
- set_start_addr(screen.start_addr);
-
- /* WE MUST DO A DUMMY READ OF THE INPUT STATUS REGISTER TO INITIALIZE
- THE TOGGLE OF THE ATTRIBUTE CONTROLLER (see text of article ) */
- inportb(video.isr);
-
- fill_triag(YELLOW, v1); /* draw the graphic image on the screen */
-
- /* ALL THE SCROLLING-PANNING ACTION IS HANDLED HERE */
- do {
- smooth_scroll(-100,2);
- smooth_pan(-300,1);
- smooth_scroll(100,2);
- smooth_pan(300,1);
- } while (!kbhit());
-
- /* A KEY WAS HIT -- RETURN TO 80 COLUMN COLOR TEXT MODE AND EXIT */
- getch();
- regs.x.ax = 0X0003;
- int86(0X10, ®s, ®s);
- }
-
-
- /* Fill an isosceles triangle with one side contiguous with a scan line and
- an apex at the top.
- */
-
- int fill_triag(int color, int v[][2])
- {
- int y, start, end;
- double left_slope, right_slope, x0, x1, x2, y0, y1, y2;
-
- x0 = v[0][0];
- x1 = v[1][0];
- x2 = v[2][0];
- y0 = v[0][1];
- y1 = v[1][1];
- y2 = v[2][1];
-
- left_slope = (x1 - x0)/(y1 - y0); /* Compute slopes */
- right_slope = (x2 - x0)/(y2 - y0); /* Compute slopes */
- for (y = y0; y <= y1; y++) { /* Loop over raster lines */
- start = x0 + (y - y0)*left_slope;
- end = x0 + (y - y0)*right_slope;
- scanline(start,end,y,color); /* Fill next section */
- }
-
- return (0);
- }
-
-
- void scanline(unsigned start, unsigned stop, unsigned raster, int color)
- {
- #define GRAPHICSC 0X03CE
- #define SEQUENCER 0X03C4
- #define BIT_MASK 8
-
- unsigned i, mask;
- BYTE oddbits, byte, far *s_offset;
- int scan_len;
-
- scan_len = stop - start; /* length -1 in pixels */
-
- /* --- Load SET/RESET registers with current color */
-
- outport(GRAPHICSC, color << 8); /* move color into reset register */
- outport(GRAPHICSC, 0X0F01); /* enable use of reset register */
- outport(SEQUENCER, 0X0F02); /* enable all planes for write */
-
- /* ----------- COMPUTE ADDRESS AND MASK FOR FIRST PIXEL ------------- */
- s_offset = video.base + screen.logical_width*raster + (start >> 3);
- if ( (oddbits = start & 7) != 0) {
- mask = 0X00FF >> oddbits;
- scan_len += oddbits;
- scan_len -= 8;
- if (scan_len < 0) {
- scan_len = (~scan_len) + 1;
- mask = mask >> (BYTE) scan_len;
- mask = mask << (BYTE) scan_len;
- scan_len = 0;
- }
- outport(GRAPHICSC, (mask << 8) | BIT_MASK); /* unmask bit mask */
- byte = *s_offset; /* latch data */
- *s_offset++ = byte; /* write data */
- }
-
- /* ---------------- WRITE COMPLETE BYTES -------------------- */
- if (scan_len >= 8) {
- outport(GRAPHICSC, (0XFFFF << 8) | BIT_MASK); /* unmask bit mask */
- for (i=0; i < (scan_len >> 3); i++) *s_offset++ = byte;
- }
-
- /* --- COMPUTE ADDRESS AND MASK FOR LAST PIXEL ------------- */
-
- if ( (oddbits = scan_len & 7) != 0) {
- mask = (0XFF >> oddbits) ^ 0XFF;
- outport(GRAPHICSC, (mask << 8) | BIT_MASK);
- byte = *s_offset; /* latch data */
- *s_offset++ = byte; /* write data */
- }
-
-
- /* RESTORE BIT MASK AND SET/RESET REGISTERS */
- outport(GRAPHICSC, (0XFFFF << 8) | BIT_MASK);
- outport(GRAPHICSC, 0X0001);
- }
-
-
-
- /* SMOOTH_SCROLL scrolls the EGA video buffer the number of scan lines
- indicated in "count" at a speed of "speed" scan lines per vertical retrace.
- */
- unsigned smooth_scroll(int count, unsigned speed)
- {
-
- unsigned i, max_count;
-
- max_count = (count < 0) ? -count : count;
-
- /* GET THE START ADDRESS OF THE SCREEN BUFFER */
- outportb(video.crtc, START_ADDRESS_HIGH); /* High byte */
- screen.start_addr = inportb(video.crtc+1) << 8;
- outportb(video.crtc, START_ADDRESS_LOW); /* Low byte */
- screen.start_addr |= inportb(video.crtc+1);
-
- /* COUNT > 0 => SCROLL SCREEN IMAGE UPWARDS. */
- for(i=0;i < max_count; i+=speed) {
- screen.start_addr = (count > 0) ?
- screen.start_addr + screen.logical_width*speed :
- screen.start_addr - screen.logical_width*speed;
- /* wait for the end of a vertical retrace */
- while (inportb(video.isr) & 8);
- /* wait for the next vertical retrace */
- while (!(inportb(video.isr) & 8));
- set_start_addr(screen.start_addr);
- }
- return (screen.start_addr);
- }
-
-
- /* SMOOTH_PAN
- This function invokes smooth panning on the EGA/VGA. The function calculates
- the number of scan lines per row. The speed variable adjusts the speed in
- pixels per vertical retrace and takes values in the range 1-8.
- */
- unsigned smooth_pan(int count, unsigned speed)
- {
- unsigned i;
-
- /* count greater than zero (move viewport to the right) */
- if (count>0 && !right_edge) for(i=0;i<count;) {
-
- /* if we have scrolled a full character, reset start address */
- if (hpel>=8) {
- screen.start_addr++;
- left_edge = FALSE;
- if (!(screen.start_addr % (screen.logical_width))) right_edge = TRUE;
- if (!right_edge) hpel %= 8; /* reset the pel counter */
- else {
- hpel = 0;
- i = count - 1;
- }
- set_start_addr(screen.start_addr);
- }
- for(;hpel < 8 && i < count;i+=speed, hpel+=speed) set_pel_pan(hpel);
- }
-
- /* count less than zero (move viewport to the left) */
- else if (count<0) {
- if (hpel>7) hpel = hpel - 8;
- for(i=0;i<(-count) ;) {
- /* if we have scrolled a full character, reset start address */
- if (hpel<0 && !left_edge) {
- screen.start_addr--;
- right_edge = FALSE;
- if (!(screen.start_addr % (screen.logical_width))) left_edge = TRUE;
- hpel = 8 + hpel;
- set_start_addr(screen.start_addr);
- }
- else if (hpel<0 && left_edge) i = (-count);
- for(;hpel >= 0 && i < (-count);i+=speed, hpel-=speed) set_pel_pan(hpel);
- }
- }
- return (screen.start_addr);
- }
-
-
- /* SET_LOGICAL_SCREEN_WIDTH defines an EGA/VGA screen width for smooth panning
- and sets the the global variable "screen.cols." screen.cols must be restored
- when smooth panning is finished or subsequent screen writes will address the
- wrong screen locations.
- l_width is the width of the logical screen in bytes. Max 512.
- */
- unsigned set_logical_screen_width(unsigned l_width)
- {
- l_width = (l_width > 512) ? 512 : l_width;
-
- /* set screen_cols */
- screen.cols = l_width;
-
- /* set logical screen width */
- l_width >>= 1; /* convert to words */
- outport(video.crtc, (l_width << 8) | OFFSET_REG);
-
- return (l_width << 1);
- }
-
-
- /* SET_START_ADDRESS -- Sets the start address of the screen. I.e. the */
- /* address that occupies the top left of the screen. */
- void set_start_addr(unsigned start_addr)
- {
- /* address the start address high register */
- outport(video.crtc, (start_addr & 0XFF00) | START_ADDRESS_HIGH);
-
- /* address the start address low register */
- outport(video.crtc, (start_addr << 8) | START_ADDRESS_LOW);
- }
-
-
- /* SET_PEL_PAN -- Sets the horizontal pel panning register to the value */
- /* specified in "hpel". Called by smooth_pan() */
- void set_pel_pan(int hpel)
- {
- /* first wait for end of vertical retrace */
- while (inportb(video.isr) & 8);
-
- /* wait for next vertical retrace */
- while (!(inportb(video.isr) & 8));
-
- /* address the horizontal pel paning register */
- outportb(AC_INDEX, AC_HPP);
- outportb(AC_INDEX, hpel);
- }