home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
microcrn
/
issue_39.arc
/
HERCLIB.FIG
< prev
next >
Wrap
Text File
|
1987-12-01
|
11KB
|
401 lines
/* HERCLIB.C Routines for the Hercules card
This file contains graphics support functions for the Hercules card. See
Micro Cornucopia issue #39 for an article on the subject.
I used Turbo C version 1.5 compact model for compiulation.
12-1-87 Larry Fogg
*/
#include <stdlib.h>
#include <dos.h>
#define boolean char
#define yes 1
#define no 0
#define index 0x3b4 /* 6845 ports */
#define data 0x3b5
#define mode 0x3b8 /* Herc ports */
#define status 0x3ba
#define config 0x3bf
const char normal = 0x07; /* character attributes for direct screen writes */
const char reverse = 0x70;
const char under_line = 0x01;
const char normal_blink = 0x87;
const char reverse_blink = 0xf0;
const char under_blink = 0x81;
const int page0 = 0xb000; /* base address of video pages */
const int page1 = 0xb800;
const int text_base = 0xb000; /* base address of text page */
const int max_col = 719; /* Herc parameters */
const int max_row = 347;
const int screen_size = 0x8000; /* bytes per page */
int page_drawn, page_viewed; /* current drawing and viewing pages */
void init () /* set initial values for global variables */
{
page_drawn = page0;
page_viewed = page0;
} /* init */
boolean herc_there () /* test for presence of Hercules card */
{
unsigned i;
geninterrupt (0x11);
if ((_AX & 0x30) == 0x30) /* check for monochrome card presence */
for (i = 0; i < 0x800; i++) /* is it a Herc */
if ((inportb (status) & 0x80)) /* watch bit 7 */
return yes;
return no;
} /* herc_there */
void screen_off ()
{
outportb (mode, 2);
} /* screen_off */
void set_page_viewed (int page)
{
if (page == page0)
outportb (mode, 0x0a);
else
outportb (mode, 0x8a);
page_viewed = page;
} /* set_page_viewed */
void set_page_drawn (int page)
{
page_drawn = page;
} /* set_page_drawn */
void clear_gr_scr (int page)
{
int i;
if (page_viewed == page)
screen_off (); /* turn off screen if page is displayed */
for (i = 0; i < 0x3FFF; i++)
poke (page, 2 * i, 0); /* turn off all bits */
if (page_viewed == page) /* turn screen on again */
set_page_viewed (page);
} /* clear_gr_scr */
void clear_txt_scr ()
{
int i;
for (i = 0; i <= 0x3fff; i++)
poke (text_base, 2 * i, 0x0700); /* fill text page with nulls & attrib 7 */
} /* clear_txt_scr */
void gotoXY (char X, char Y) /* position the cursor */
{
_AH = 2; /* service 2 */
_BH = 0;
_DH = Y; /* row number */
_DL = X; /* column number */
geninterrupt (0x10);
} /* gotoXY */
void scr_write (int X, int Y, char str [81], char attrib)
{ /* direct memory write of text */
int i, offset;
i = 0;
offset = 2 * (80 * Y + X); /* find memory offset of first char in str */
while (str [i] != '\0') /* poke each char-attribute pair */
{
pokeb (text_base, offset, str [i]);
pokeb (text_base, ++offset, attrib);
i++;
offset++;
}
gotoXY (X + i, Y); /* position cursor at end of str */
} /* scr_write */
void set_graphics ()
{
char i;
char params [12] = {0x35, 0x2d, 0x2e, 0x07, 0x5b, 0x02,
0x57, 0x57, 0x02, 0x03, 0x00, 0x00};
outportb (config, 3); /* allows both graphics pages */
screen_off ();
for (i = 0; i < 12; i++) /* program 6845 registers for graphics */
{
outportb (index, i);
outportb (data, params [i]);
}
clear_gr_scr (page0);
clear_gr_scr (page1); /* clear and turn on screen */
} /* set_graphics */
void set_text ()
{
char i;
char params [12] = {0x61, 0x50, 0x52, 0x0f, 0x19, 0x06,
0x19, 0x19, 0x02, 0x0d, 0x0b, 0x0c};
outportb (config, 0); /* lock out graphics modes */
outportb (mode, 0); /* set text mode and blank screen */
for (i = 0; i < 12; i++) /* program 6845 registers for text */
{
outportb (index, i);
outportb (data, params [i]);
}
clear_txt_scr ();
outportb (mode, 0x28); /* enable blink and turn on screen */
} /* set_text */
void save_screen (char fname [13], int page) /* write to disk */
{
FILE *f;
char far *screen;
screen = page * 0x10000; /* wierd but it works */
f = fopen (fname, "w");
fwrite (screen, screen_size, 1, f);
fclose (f);
} /* save_screen */
void get_screen (char fname [13], int page) /* read from disk */
{
FILE *f;
char far *screen;
screen = page * 0x10000;
f = fopen (fname, "r");
screen_off ();
fread (screen, screen_size, 1, f);
set_page_viewed (page);
fclose (f);
} /* get_screen */
void draw_point (int col, int row, boolean fill)
{
int byte_ofs; /* offset within page for byte containing the point */
char mask; /* locates point within the byte */
mask = 1 << (7 - (col % 8));
byte_ofs = 0x2000 * (row % 4) + 90 * (row / 4) + (col / 8);
if (fill) /* draw the point */
pokeb (page_drawn, byte_ofs, peekb (page_drawn, byte_ofs) | mask);
else /* erase the point */
pokeb (page_drawn, byte_ofs, peekb (page_drawn, byte_ofs) & ~mask);
} /* draw_point */
void draw_byte (int offset, boolean fill) /* draw 8 points at once for speed */
{
if (fill)
poke (page_drawn, offset, 0xff);
else
poke (page_drawn, offset, 0x00);
} /* draw_byte */
void draw_line (int X1, int Y1, int X2, int Y2, boolean on)
{ /* uses Bresenham algorithm to draw a line */
int dX, dY; /* vector components */
int row, col,
final, /* final row or column number */
G, /* used to test for new row or column */
inc1, /* G increment when row or column doesn't change */
inc2; /* G increment when row or column changes */
boolean pos_slope;
dX = X2 - X1; /* find vector components */
dY = Y2 - Y1;
pos_slope = (dX > 0); /* is slope positive? */
if (dY < 0)
pos_slope = !pos_slope;
if (abs (dX) > abs (dY)) /* shallow line case */
{
if (dX > 0) /* determine start point and last column */
{
col = X1;
row = Y1;
final = X2;
}
else
{
col = X2;
row = Y2;
final = X1;
}
inc1 = 2 * abs (dY); /* determine increments and initial G */
G = inc1 - abs (dX);
inc2 = 2 * (abs (dY) - abs (dX));
if (pos_slope)
while (col <= final) /* step through columns chacking for new row */
{
draw_point (col, row, on);
col++;
if (G >= 0) /* it's time to change rows */
{
row++; /* positive slope so increment through the rows */
G += inc2;
}
else /* stay at the same row */
G += inc1;
}
else
while (col <= final) /* step through columns checking for new row */
{
draw_point (col, row, on);
col++;
if (G > 0) /* it's time to change rows */
{
row--; /* negative slope so decrement through the rows */
G += inc2;
}
else /* stay at the same row */
G += inc1;
}
} /* if |dX| > |dY| */
else /* steep line case */
{
if (dY > 0) /* determine start point and last row */
{
col = X1;
row = Y1;
final = Y2;
}
else
{
col = X2;
row = Y2;
final = Y1;
}
inc1 = 2 * abs (dX); /* determine increments and initial G */
G = inc1 - abs (dY);
inc2 = 2 * (abs (dX) - abs (dY));
if (pos_slope)
while (row <= final) /* step through rows checking for new column */
{
draw_point (col, row, on);
row++;
if (G >= 0) /* it's time to change columns */
{
col++; /* positive slope so increment through the columns */
G += inc2;
}
else /* stay at the same column */
G += inc1;
}
else
while (row <= final) /* step throuth rows checking for new column */
{
draw_point (col, row, on);
row++;
if (G > 0) /* it's time to change columns */
{
col--; /* negative slope so decrement through the columns */
G += inc2;
}
else /* stay at the same column */
G += inc1;
}
}
} /* draw_line */
void draw_box (int X1, int Y1, int X2, int Y2, boolean fill)
{ /* fast box fill - does a byte at a time when it can */
int row, col, i,
left_bits, right_bits, byte_draws;
int byte_ofs;
left_bits = 8 - (X1 % 8); /* individual bits that need to be drawn */
right_bits = (X2 % 8);
byte_draws = (X2 - X1 - left_bits) / 8; /* number of byte draws to do */
for (row = Y1; row <= Y2; row++)
{
for (col = X1; col <= X1 + left_bits; col++) /* draw the left side bits */
draw_point (col, row, fill);
for (col = X2 - right_bits; col <= X2; col++) /* draw the right bits */
draw_point (col, row, fill);
byte_ofs = 0x2000 * (row % 4) + 90 * (row / 4) + ((X1 + left_bits) / 8);
for (i = byte_ofs; i <= byte_ofs + byte_draws; i++) /* draw the bytes */
draw_byte (i, fill);
}
} /* draw_box */