📄 graf.c
字号:
/*
* grafix --- graf.c
*
* graphics interface
*
* Written 4/87 by Scott Snyder (ssnyder@romeo.caltech.edu or @citromeo.bitnet)
*
* 5/29/87 sss - fixed bug in box() and allow for different memory models
*
*/
#include "macros.h"
#include "graf.h"
#include "grafsys.h"
#include <dos.h>
#define int_video 0x10
#define video_point 0x0c
#define ega_altsel 0x12
#define egaalt_info 0x10
/* utility macros */
#define swap(a, b) {int _tmp; _tmp=a; a=b; b=_tmp;}
#define inrange(a, x, b) ((a)<=(x) && (x)<=(b))
#define clipto(x, lo, hi) { \
if (x < lo) \
x = lo; \
else if (x > hi) \
x = hi; \
}
/*****************************************************************************
* variable definitions *
*****************************************************************************/
unsigned NEAR g_card; /* graphics card we're using */
unsigned NEAR g_display; /* type of display we're using */
g_obj far * NEAR g_drawbuf; /* graphics drawing buffer */
g_obj far * NEAR g_physbuf; /* physical screen address */
g_obj far * NEAR g_virtbuf; /* virtual buffer address */
unsigned NEAR g_colormax; /* maximum color value */
unsigned NEAR g_xsize, NEAR g_ysize; /* physical size of screen */
unsigned NEAR g_xchsize, NEAR g_ychsize; /* size of screen in characters */
unsigned NEAR g_xor; /* xor mode flag */
unsigned NEAR g_bufflg; /* buffered mode flag */
unsigned NEAR g_pages; /* number of pagse available */
unsigned NEAR g_curpage; /* page currently visible */
int NEAR g_xcliplo, NEAR g_xcliphi; /* clipping boundaries */
int NEAR g_ycliplo, NEAR g_ycliphi;
float NEAR g_aspect; /* aspect ratio */
/*****************************************************************************
* interfaces to graphics drivers *
*****************************************************************************/
/************************* calls for internal use only ***********************/
STATIC void nocl_regfill(x1, y1, x2, y2, c)
unsigned x1, y1, x2, y2, c;
{
switch(g_card) {
case (CGA): CGA_regfill(x1, y1, x2, y2, c); break;
case (EGA): EGA_regfill(x1, y1, x2, y2, c); break;
}
}
STATIC void nocl_point(x, y, c)
unsigned x, y, c;
{
switch(g_card) {
case (CGA): CGA_point(x, y, c); break;
case (EGA): EGA_point(x, y, c); break;
}
}
STATIC void nocl_line(x1, y1, x2, y2, c)
unsigned x1, y1, x2, y2, c;
{
switch(g_card) {
case (CGA): CGA_line(x1, y1, x2, y2, c); break;
case (EGA): EGA_line(x1, y1, x2, y2, c); break;
}
}
STATIC void write_pix(x1, y1, x2, y2, c)
int x1, y1, x2, y2;
unsigned c;
{
switch(g_card) {
case (CGA): CGA_write_pix(x1, y1, x2, y2, c); break;
case (EGA): EGA_write_pix(x1, y1, x2, y2, c); break;
}
}
/* set up for plotting mucho points */
STATIC void point_set(c)
unsigned c;
{
switch(g_card) {
case (CGA): CGA_point_set(c); break;
case (EGA): EGA_point_set(c); break;
}
}
STATIC void point_res()
{
switch(g_card) {
case (CGA): CGA_point_res(); break;
case (EGA): EGA_point_res(); break;
}
}
/******************** calls safe for anyone to use **************************/
void g_clearall(c)
unsigned c;
{
switch(g_card) {
case (CGA): CGA_clearall(c); break;
case (EGA): EGA_clearall(c); break;
}
}
void g_show()
{
switch(g_card) {
case (CGA): CGA_show(); break;
case (EGA): EGA_show(); break;
}
}
void g_setback(c)
unsigned c;
{
switch(g_card) {
case (CGA): CGA_setback(c); break;
case (EGA): EGA_setback(c); break;
}
}
void g_setpal(pallette, value)
unsigned pallette, value;
{
switch(g_card) {
case (CGA): CGA_setpal(pallette, value); break;
case (EGA): EGA_setpal(pallette, value); break;
}
}
/* g_open also sets clipping boundaries to the physical screen size */
/* and initializes other things... */
void g_open(mode)
unsigned mode;
{
switch(g_card) {
case (CGA): CGA_gopen(mode); break;
case (EGA): EGA_gopen(mode); break;
}
g_xcliplo = 0;
g_ycliplo = 0;
g_xcliphi = g_xsize-1;
g_ycliphi = g_ysize-1;
g_xor = g_bufflg = 0;
/* set g_drawbuf to something appropriately */
g_setbuf(g_bufflg);
}
void g_close()
{
switch(g_card) {
case (CGA): CGA_gclose(); break;
case (EGA): EGA_gclose(); break;
}
}
void g_writech(row, col, ch, c, page)
unsigned row, col, c;
char ch;
int page;
{
switch(g_card) {
case (CGA): CGA_writech(row, col, ch, c, page); break;
case (EGA): EGA_writech(row, col, ch, c, page); break;
}
}
/***************************************************************************
* graphics drawing and control routines *
***************************************************************************/
/* fill a region with the specified color */
void g_regfill(x1, y1, x2, y2, c)
int x1, y1, x2, y2;
unsigned c;
{
if (x1 > x2)
swap(x1, x2);
if (y1 > y2)
swap(y1, y2);
if (x1 < g_xcliplo)
x1 = g_xcliplo;
else if (x1 > g_xcliphi)
return;
if (x2 < g_xcliplo)
return;
else if (x2 > g_xcliphi)
x2 = g_xcliphi;
if (y1 < g_ycliplo)
y1 = g_ycliplo;
else if (y1 > g_ycliphi)
return;
if (y2 < g_ycliplo)
return;
else if (y2 > g_ycliphi)
y2 = g_ycliphi;
nocl_regfill(x1, y1, x2, y2, c);
}
/* plot a point */
void g_point(x, y, c)
int x, y;
unsigned c;
{
if (inrange(g_xcliplo, x, g_xcliphi) &&
inrange(g_ycliplo, y, g_ycliphi))
nocl_point(x, y, c);
}
/* routine to clip one endpoint of a line */
STATIC int clipln(x1,y1,xc,yc,x2,y2)
int x1,y1,x2,y2,*xc,*yc;
{
int delx,dely,xx,yy;
if (x1 >= g_xcliplo && x1 <= g_xcliphi &&
y1 >= g_ycliplo && y1 <= g_ycliphi) {
*xc=x1; *yc=y1;
return(1);
}
dely=y2-y1;
delx=x2-x1;
if (y1 > g_ycliphi || y1 < g_ycliplo) {
if (dely == 0)
return(0);
if (y1 > g_ycliphi) {
if (dely > 0 || y2 > g_ycliphi) return (0);
yy=g_ycliphi;
}
else {
if (dely < 0 || y2 < g_ycliplo) return(0);
yy=g_ycliplo;
}
xx=(float)(yy-y1)*delx/dely+x1;
if (xx >= g_xcliplo && xx <= g_xcliphi) {
*xc=xx; *yc=yy;
return(1);
}
}
if (x1 > g_xcliphi || x1 < g_xcliplo) {
if (delx == 0)
return(0);
if (x1 > g_xcliphi) {
if (delx > 0 || x2 > g_xcliphi) return(0);
xx=g_xcliphi;
}
else {
if (delx < 0 || x2 < g_xcliplo) return(0);
xx=g_xcliplo;
}
yy=(float)(xx-x1)*dely/delx+y1;
if (yy >= g_ycliplo && yy <= g_ycliphi) {
*xc=xx; *yc=yy;
return(1);
}
}
return(0);
}
/* draw a clipped line */
void g_line(x1,y1,x2,y2,c)
int x1,y1,x2,y2;
unsigned c;
{
if (clipln(x1,y1,&x1,&y1,x2,y2) &&
clipln(x2,y2,&x2,&y2,x1,y1)) {
nocl_line(x1,y1,x2,y2,c);
}
}
/* draw an ellipse with aspect aspect and half-major axis length r_sum_m */
/* from a routine by Tim Hogan in Dr. Dobb's Journal May '85 p. 40 */
void g_ellipse(x, y, r_sub_m, aspect, c)
int x,y,r_sub_m;
unsigned c;
float aspect;
{
long alpha, beta, two_alpha, four_alpha, two_beta, four_beta, d;
int row, col, two_x, two_y, rel_x, rel_y;
double square_aspect;
if (aspect < 0.004) aspect = 0.004;
square_aspect = aspect*aspect;
if (aspect < 1.0) {
alpha = (long)r_sub_m * (long)r_sub_m;
beta = alpha * square_aspect;
row = y + r_sub_m*aspect;
}
else {
beta = (long)r_sub_m * (long)r_sub_m;
alpha = beta / square_aspect;
row = y + r_sub_m;
}
if (alpha == 0L) alpha = 1L;
if (beta == 0L) beta = 1L;
col = x;
two_x = x<<1;
two_y = y<<1;
rel_y = row-y;
two_alpha = alpha<<1;
four_alpha = alpha<<2;
two_beta = beta<<1;
four_beta = beta<<2;
d = two_alpha*((long)(rel_y-1)*rel_y) + alpha + two_beta*(1-alpha);
point_set(c); /* set up for point plotting */
while (alpha*(rel_y = row-y) > beta*(rel_x = col-x)) {
write_pix(col, row, two_x-col, two_y-row, c);
if (d>=0) {
d += four_alpha*(1-rel_y);
row--;
}
d += two_beta*(3+(rel_x<<1));
col++;
}
d = two_beta * ((long)rel_x * (rel_x+1)) + two_alpha*((long)rel_y*(rel_y-2)+1) +
beta*(1-two_alpha);
while ((rel_y = row-y) + 1) {
write_pix(col, row, two_x-col, two_y-row, c);
if (d<=0) {
d += four_beta*(1+col-x);
col++;
}
d += two_alpha*(3-(rel_y<<1));
row--;
}
point_res(); /* reset the graphics device */
}
/* draw a circle */
void g_circle(x, y, r, c)
int x, y, r;
unsigned c;
{
g_ellipse(x, y, r, g_aspect, c);
}
/* draw a box */
void g_box(x1, y1, x2, y2, c)
int x1, y1, x2, y2;
unsigned c;
{
g_line(x1, y1, x2, y1, c);
g_line(x2, y1, x2, y2, c);
g_line(x2, y2, x1, y2, c);
g_line(x1, y2, x1, y1, c);
}
/* set xor mode */
void g_setxor(flag)
unsigned flag;
{
g_xor = flag;
}
/* set clipping boundaries */
void g_setclip(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
if (x1 > x2)
swap(x1, x2);
if (y1 > y2)
swap(y1, y2);
clipto(x1, 0, g_xsize-1);
clipto(x2, 0, g_xsize-1);
clipto(y1, 0, g_ysize-1);
clipto(y2, 0, g_ysize-1);
g_xcliplo = x1;
g_xcliphi = x2;
g_ycliplo = y1;
g_ycliphi = y2;
}
/* clear screen within clipping boundaries */
void g_clear(c)
unsigned c;
{
nocl_regfill(g_xcliplo, g_ycliplo, g_xcliphi, g_ycliphi, c);
}
/* set buffered mode flag and initialize drawbuf appropriately */
void g_setbuf(flag)
unsigned flag;
{
g_bufflg = flag;
if (flag)
g_drawbuf = g_virtbuf;
else
g_drawbuf = g_physbuf;
}
/* initialize graphics system */
void g_init(card, display)
unsigned card;
unsigned display; /* ignored if card = 0 */
{
unsigned swt;
union REGS inregs, outregs;
/* try to get EGA information. if we have enough memory for 2 hi-res
pages, then say we have an EGA. if not, or if the card does not
respond, assume we have a CGA. if argument is nonzero however, force
result to that.
*/
if (card == 0) {
inregs.h.ah = ega_altsel;
inregs.h.bl = egaalt_info;
int86(int_video, &inregs, &outregs);
if (outregs.h.bl != 3) { /* not valid | mem. < 256k */
g_card = CGA;
g_display = CD;
}
else {
g_card = EGA;
/* now look at the adapter switch settings (in cl) and try to figure
out what sort of display is attached */
swt = outregs.h.cl & 0x0e;
swt = (swt >= 6 ? swt-6 : swt);
if (swt == 4)
g_display = MO;
else if (swt == 2)
g_display = EN;
else if (swt == 0)
g_display = CD;
else
g_display = CD;
}
}
else {
g_card = card;
g_display = display;
}
g_xor = 0;
g_bufflg = 0;
g_xcliplo = g_xcliplo = g_ycliphi = g_ycliplo = 0;
}
/* write a string tty style with color c at row, col */
void g_writestr(row, col, s, c, page)
unsigned row, col;
unsigned c;
char *s;
int page;
{
while (*s) {
if (col >= g_xchsize) { /* do wrapping */
col = 0;
row++;
}
if (row >= g_ychsize) /* abort if we run out of screen */
return;
if (*s == '\012') /* newline */
col = g_xchsize; /* force a wrap next time around */
else if (*s == '\015') /* ignore any carriage returns (for compat) */
;
else {
g_writech (row, col, *s, c, page);
col++;
}
s++;
}
}
/* get information about physical graphics device */
void g_info(p)
struct g_info *p;
{
p->card = g_card;
p->display = g_display;
p->xsize = g_xsize;
p->ysize = g_ysize;
p->colormax = g_colormax;
p->pages = g_pages;
p->curpage = g_curpage;
p->xchsize = g_xchsize;
p->ychsize = g_ychsize;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -