home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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;
- }
-