home *** CD-ROM | disk | FTP | other *** search
/ MS DOS Archives 1 / MS-DOS_Archives_Volume_One_Walnut_Creek.iso / msdos / graphics / grafxlib.arc / GRAF.C < prev    next >
C/C++ Source or Header  |  1987-08-31  |  12KB  |  539 lines

  1. /*
  2.  * grafix --- graf.c
  3.  *
  4.  * graphics interface
  5.  *
  6.  * Written 4/87 by Scott Snyder (ssnyder@romeo.caltech.edu or @citromeo.bitnet)
  7.  *
  8.  * 5/29/87 sss - fixed bug in box() and allow for different memory models
  9.  *
  10.  */
  11.  
  12. #include "macros.h"
  13. #include "graf.h"
  14. #include "grafsys.h"
  15. #include <dos.h>
  16.  
  17. #define int_video   0x10
  18. #define video_point 0x0c
  19. #define ega_altsel  0x12
  20. #define egaalt_info 0x10
  21.  
  22. /* utility macros */
  23.  
  24. #define swap(a, b) {int _tmp; _tmp=a; a=b; b=_tmp;}
  25. #define inrange(a, x, b) ((a)<=(x) && (x)<=(b))
  26. #define clipto(x, lo, hi) { \
  27.   if (x < lo)               \
  28.     x = lo;                 \
  29.   else if (x > hi)          \
  30.     x = hi;                 \
  31. }
  32.  
  33. /*****************************************************************************
  34.  *                            variable definitions                           *
  35.  *****************************************************************************/
  36.  
  37. unsigned NEAR g_card;        /* graphics card we're using */
  38. unsigned NEAR g_display;    /* type of display we're using */
  39.  
  40. g_obj far * NEAR g_drawbuf;    /* graphics drawing buffer */
  41. g_obj far * NEAR g_physbuf;    /* physical screen address */
  42. g_obj far * NEAR g_virtbuf;    /* virtual buffer address  */
  43. unsigned NEAR g_colormax;    /* maximum color value     */
  44. unsigned NEAR g_xsize, NEAR g_ysize; /* physical size of screen */
  45. unsigned NEAR g_xchsize, NEAR g_ychsize; /* size of screen in characters */
  46. unsigned NEAR g_xor;        /* xor mode flag */
  47. unsigned NEAR g_bufflg;        /* buffered mode flag */
  48. unsigned NEAR g_pages;        /* number of pagse available */
  49. unsigned NEAR g_curpage;    /* page currently visible */
  50.  
  51. int NEAR g_xcliplo, NEAR g_xcliphi; /* clipping boundaries */
  52. int NEAR g_ycliplo, NEAR g_ycliphi;
  53.  
  54. float NEAR g_aspect;        /* aspect ratio */
  55.  
  56. /*****************************************************************************
  57.  *                       interfaces to graphics drivers                      *
  58.  *****************************************************************************/
  59.  
  60. /************************* calls for internal use only ***********************/
  61.  
  62. STATIC void nocl_regfill(x1, y1, x2, y2, c)
  63. unsigned x1, y1, x2, y2, c;
  64. {
  65.   switch(g_card) {
  66.     case (CGA): CGA_regfill(x1, y1, x2, y2, c); break;
  67.     case (EGA): EGA_regfill(x1, y1, x2, y2, c); break;
  68.   }
  69. }
  70.  
  71. STATIC void nocl_point(x, y, c)
  72. unsigned x, y, c;
  73. {
  74.   switch(g_card) {
  75.     case (CGA): CGA_point(x, y, c); break;
  76.     case (EGA): EGA_point(x, y, c); break;
  77.   }
  78. }
  79.  
  80. STATIC void nocl_line(x1, y1, x2, y2, c)
  81. unsigned x1, y1, x2, y2, c;
  82. {
  83.   switch(g_card) {
  84.     case (CGA): CGA_line(x1, y1, x2, y2, c); break;
  85.     case (EGA): EGA_line(x1, y1, x2, y2, c); break;
  86.   }
  87. }
  88.  
  89. STATIC void write_pix(x1, y1, x2, y2, c)
  90. int x1, y1, x2, y2;
  91. unsigned c;
  92. {
  93.   switch(g_card) {
  94.     case (CGA): CGA_write_pix(x1, y1, x2, y2, c); break;
  95.     case (EGA): EGA_write_pix(x1, y1, x2, y2, c); break;
  96.   }
  97. }
  98.  
  99. /* set up for plotting mucho points */
  100.  
  101. STATIC void point_set(c)
  102. unsigned c;
  103. {
  104.   switch(g_card) {
  105.     case (CGA): CGA_point_set(c); break;
  106.     case (EGA): EGA_point_set(c); break;
  107.   }
  108. }
  109.  
  110. STATIC void point_res()
  111. {
  112.   switch(g_card) {
  113.     case (CGA): CGA_point_res(); break;
  114.     case (EGA): EGA_point_res(); break;
  115.   }
  116. }
  117.  
  118. /******************** calls safe for anyone to use **************************/
  119.  
  120. void g_clearall(c)
  121. unsigned c;
  122. {
  123.   switch(g_card) {
  124.     case (CGA): CGA_clearall(c); break;
  125.     case (EGA): EGA_clearall(c); break;
  126.   }
  127. }
  128.  
  129. void g_show()
  130. {
  131.   switch(g_card) {
  132.     case (CGA): CGA_show(); break;
  133.     case (EGA): EGA_show(); break;
  134.   }
  135. }
  136.  
  137. void g_setback(c)
  138. unsigned c;
  139. {
  140.   switch(g_card) {
  141.     case (CGA): CGA_setback(c); break;
  142.     case (EGA): EGA_setback(c); break;
  143.   }
  144. }
  145.  
  146. void g_setpal(pallette, value)
  147. unsigned pallette, value;
  148. {
  149.   switch(g_card) {
  150.     case (CGA): CGA_setpal(pallette, value); break;
  151.     case (EGA): EGA_setpal(pallette, value); break;
  152.   }
  153. }
  154.  
  155. /* g_open also sets clipping boundaries to the physical screen size */
  156. /* and initializes other things... */
  157.  
  158. void g_open(mode)
  159. unsigned mode;
  160. {
  161.   switch(g_card) {
  162.     case (CGA): CGA_gopen(mode); break;
  163.     case (EGA): EGA_gopen(mode); break;
  164.   }
  165.   g_xcliplo = 0;
  166.   g_ycliplo = 0;
  167.   g_xcliphi = g_xsize-1;
  168.   g_ycliphi = g_ysize-1;
  169.  
  170.   g_xor = g_bufflg = 0;
  171.  
  172. /* set g_drawbuf to something appropriately */
  173.  
  174.   g_setbuf(g_bufflg);
  175. }
  176.  
  177. void g_close()
  178. {
  179.   switch(g_card) {
  180.     case (CGA): CGA_gclose(); break;
  181.     case (EGA): EGA_gclose(); break;
  182.   }
  183. }
  184.  
  185. void g_writech(row, col, ch, c, page)
  186. unsigned row, col, c;
  187. char ch;
  188. int page;
  189. {
  190.   switch(g_card) {
  191.     case (CGA): CGA_writech(row, col, ch, c, page); break;
  192.     case (EGA): EGA_writech(row, col, ch, c, page); break;
  193.   }
  194. }
  195.  
  196. /***************************************************************************
  197.  *                    graphics drawing and control routines                *
  198.  ***************************************************************************/
  199.  
  200. /* fill a region with the specified color */
  201.  
  202. void g_regfill(x1, y1, x2, y2, c)
  203. int x1, y1, x2, y2;
  204. unsigned c;
  205. {
  206.   if (x1 > x2)
  207.     swap(x1, x2);
  208.   if (y1 > y2)
  209.     swap(y1, y2);
  210.  
  211.   if (x1 < g_xcliplo)
  212.     x1 = g_xcliplo;
  213.   else if (x1 > g_xcliphi)
  214.     return;
  215.  
  216.   if (x2 < g_xcliplo)
  217.     return;
  218.   else if (x2 > g_xcliphi)
  219.     x2 = g_xcliphi;
  220.  
  221.   if (y1 < g_ycliplo)
  222.     y1 = g_ycliplo;
  223.   else if (y1 > g_ycliphi)
  224.     return;
  225.  
  226.   if (y2 < g_ycliplo)
  227.     return;
  228.   else if (y2 > g_ycliphi)
  229.     y2 = g_ycliphi;
  230.  
  231.   nocl_regfill(x1, y1, x2, y2, c);
  232. }
  233.  
  234. /* plot a point */
  235.  
  236. void g_point(x, y, c)
  237. int x, y;
  238. unsigned c;
  239. {
  240.   if (inrange(g_xcliplo, x, g_xcliphi) &&
  241.       inrange(g_ycliplo, y, g_ycliphi))
  242.     nocl_point(x, y, c);
  243. }
  244.  
  245. /* routine to clip one endpoint of a line */
  246.  
  247. STATIC int clipln(x1,y1,xc,yc,x2,y2)
  248. int x1,y1,x2,y2,*xc,*yc;
  249. {
  250.   int delx,dely,xx,yy;
  251.  
  252.   if (x1 >= g_xcliplo && x1 <= g_xcliphi &&
  253.       y1 >= g_ycliplo && y1 <= g_ycliphi) {
  254.     *xc=x1; *yc=y1;
  255.      return(1);
  256.   }
  257.   dely=y2-y1;
  258.   delx=x2-x1;
  259.   if (y1 > g_ycliphi || y1 < g_ycliplo) {
  260.     if (dely == 0)
  261.       return(0);
  262.     if (y1 > g_ycliphi) {
  263.       if (dely > 0 || y2 > g_ycliphi) return (0);
  264.       yy=g_ycliphi;
  265.     }
  266.     else {
  267.       if (dely < 0 || y2 < g_ycliplo) return(0);
  268.       yy=g_ycliplo;
  269.     }
  270.     xx=(float)(yy-y1)*delx/dely+x1;
  271.     if (xx >= g_xcliplo && xx <= g_xcliphi) {
  272.       *xc=xx; *yc=yy;
  273.       return(1);
  274.     }
  275.   }
  276.   if (x1 > g_xcliphi || x1 < g_xcliplo) {
  277.     if (delx == 0)
  278.       return(0);
  279.     if (x1 > g_xcliphi) {
  280.       if (delx > 0 || x2 > g_xcliphi) return(0);
  281.       xx=g_xcliphi;
  282.     }
  283.     else {
  284.       if (delx < 0 || x2 < g_xcliplo) return(0);
  285.       xx=g_xcliplo;
  286.     }
  287.     yy=(float)(xx-x1)*dely/delx+y1;
  288.     if (yy >= g_ycliplo && yy <= g_ycliphi) {
  289.       *xc=xx; *yc=yy;
  290.       return(1);
  291.     }
  292.   }
  293.   return(0);
  294. }
  295.  
  296. /* draw a clipped line */
  297.  
  298. void g_line(x1,y1,x2,y2,c)
  299. int x1,y1,x2,y2;
  300. unsigned c;
  301. {
  302.   if (clipln(x1,y1,&x1,&y1,x2,y2) &&
  303.       clipln(x2,y2,&x2,&y2,x1,y1)) {
  304.     nocl_line(x1,y1,x2,y2,c);
  305.   }
  306. }
  307.  
  308. /* draw an ellipse with aspect aspect and half-major axis length r_sum_m */
  309. /* from a routine by Tim Hogan in Dr. Dobb's Journal May '85 p. 40       */
  310.  
  311. void g_ellipse(x, y, r_sub_m, aspect, c)
  312. int x,y,r_sub_m;
  313. unsigned c;
  314. float aspect;
  315. {
  316.   long alpha, beta, two_alpha, four_alpha, two_beta, four_beta, d;
  317.   int row, col, two_x, two_y, rel_x, rel_y;
  318.   double square_aspect;
  319.  
  320.   if (aspect < 0.004) aspect = 0.004;
  321.  
  322.   square_aspect = aspect*aspect;
  323.  
  324.   if (aspect < 1.0) {
  325.     alpha = (long)r_sub_m * (long)r_sub_m;
  326.     beta = alpha * square_aspect;
  327.     row = y + r_sub_m*aspect;
  328.   }
  329.   else {
  330.     beta = (long)r_sub_m * (long)r_sub_m;
  331.     alpha = beta / square_aspect;
  332.     row = y + r_sub_m;
  333.   }
  334.  
  335.   if (alpha == 0L) alpha = 1L;
  336.   if (beta  == 0L) beta  = 1L;
  337.  
  338.   col = x;
  339.   two_x = x<<1;
  340.   two_y = y<<1;
  341.   rel_y = row-y;
  342.   two_alpha  = alpha<<1;
  343.   four_alpha = alpha<<2;
  344.   two_beta   =  beta<<1;
  345.   four_beta  =  beta<<2;
  346.  
  347.   d = two_alpha*((long)(rel_y-1)*rel_y) + alpha + two_beta*(1-alpha);
  348.  
  349.   point_set(c);            /* set up for point plotting */
  350.  
  351.   while (alpha*(rel_y = row-y) > beta*(rel_x = col-x)) {
  352.     write_pix(col, row, two_x-col, two_y-row, c);
  353.     if (d>=0) {
  354.       d += four_alpha*(1-rel_y);
  355.       row--;
  356.     }
  357.     d += two_beta*(3+(rel_x<<1));
  358.     col++;
  359.   }
  360.  
  361.   d = two_beta * ((long)rel_x * (rel_x+1)) + two_alpha*((long)rel_y*(rel_y-2)+1) +
  362.       beta*(1-two_alpha);
  363.  
  364.   while ((rel_y = row-y) + 1) {
  365.     write_pix(col, row, two_x-col, two_y-row, c);
  366.     if (d<=0) {
  367.       d += four_beta*(1+col-x);
  368.       col++;
  369.     }
  370.     d += two_alpha*(3-(rel_y<<1));
  371.     row--;
  372.   }
  373.   point_res();                /* reset the graphics device */
  374. }
  375.  
  376. /* draw a circle */
  377.  
  378. void g_circle(x, y, r, c)
  379. int x, y, r;
  380. unsigned c;
  381. {
  382.   g_ellipse(x, y, r, g_aspect, c);
  383. }
  384.  
  385. /* draw a box */
  386.  
  387. void g_box(x1, y1, x2, y2, c)
  388. int x1, y1, x2, y2;
  389. unsigned c;
  390. {
  391.   g_line(x1, y1, x2, y1, c);
  392.   g_line(x2, y1, x2, y2, c);
  393.   g_line(x2, y2, x1, y2, c);
  394.   g_line(x1, y2, x1, y1, c);
  395. }
  396.  
  397. /* set xor mode */
  398.  
  399. void g_setxor(flag)
  400. unsigned flag;
  401. {
  402.   g_xor = flag;
  403. }
  404.  
  405. /* set clipping boundaries */
  406.  
  407. void g_setclip(x1, y1, x2, y2)
  408. int x1, y1, x2, y2;
  409. {
  410.   if (x1 > x2)
  411.     swap(x1, x2);
  412.   if (y1 > y2)
  413.     swap(y1, y2);
  414.  
  415.   clipto(x1, 0, g_xsize-1);
  416.   clipto(x2, 0, g_xsize-1);
  417.   clipto(y1, 0, g_ysize-1);
  418.   clipto(y2, 0, g_ysize-1);
  419.  
  420.   g_xcliplo = x1;
  421.   g_xcliphi = x2;
  422.   g_ycliplo = y1;
  423.   g_ycliphi = y2;
  424. }
  425.  
  426. /* clear screen within clipping boundaries */
  427.  
  428. void g_clear(c)
  429. unsigned c;
  430. {
  431.   nocl_regfill(g_xcliplo, g_ycliplo, g_xcliphi, g_ycliphi, c);
  432. }
  433.  
  434. /* set buffered mode flag and initialize drawbuf appropriately */
  435.  
  436. void g_setbuf(flag)
  437. unsigned flag;
  438. {
  439.   g_bufflg = flag;
  440.   if (flag)
  441.     g_drawbuf = g_virtbuf;
  442.   else
  443.     g_drawbuf = g_physbuf;
  444. }
  445.  
  446. /* initialize graphics system */
  447.  
  448. void g_init(card, display)
  449. unsigned card;
  450. unsigned display;            /* ignored if card = 0 */
  451. {
  452.   unsigned swt;
  453.   union REGS inregs, outregs;
  454.  
  455. /* try to get EGA information. if we have enough memory for 2 hi-res
  456.    pages, then say we have an EGA. if not, or if the card does not
  457.    respond, assume we have a CGA. if argument is nonzero however, force
  458.    result to that.
  459. */
  460.  
  461.   if (card == 0) {
  462.     inregs.h.ah = ega_altsel;
  463.     inregs.h.bl = egaalt_info;
  464.     int86(int_video, &inregs, &outregs);
  465.     if (outregs.h.bl != 3) {              /* not valid | mem. < 256k */
  466.       g_card = CGA;
  467.       g_display = CD;
  468.     }
  469.     else {
  470.       g_card = EGA;
  471.  
  472.   /* now look at the adapter switch settings (in cl) and try to figure
  473.      out what sort of display is attached */
  474.  
  475.       swt = outregs.h.cl & 0x0e;
  476.       swt = (swt >= 6 ? swt-6 : swt);
  477.       if (swt == 4)
  478.         g_display = MO;
  479.       else if (swt == 2)
  480.         g_display = EN;
  481.       else if (swt == 0)
  482.         g_display = CD;
  483.       else
  484.         g_display = CD;
  485.     }
  486.   }
  487.   else {
  488.     g_card = card;
  489.     g_display = display;
  490.   }
  491.  
  492.   g_xor = 0;
  493.   g_bufflg = 0;
  494.   g_xcliplo = g_xcliplo = g_ycliphi = g_ycliplo = 0;
  495. }
  496.  
  497. /* write a string tty style with color c at row, col */
  498.  
  499. void g_writestr(row, col, s, c, page)
  500. unsigned row, col;
  501. unsigned c;
  502. char *s;
  503. int page;
  504. {
  505.   while (*s) {
  506.     if (col >= g_xchsize) {    /* do wrapping */
  507.       col = 0;
  508.       row++;
  509.     }
  510.     if (row >= g_ychsize)     /* abort if we run out of screen */
  511.       return;
  512.     if (*s == '\012')        /* newline */
  513.       col = g_xchsize;        /* force a wrap next time around */
  514.     else if (*s == '\015')    /* ignore any carriage returns (for compat) */
  515.       ;
  516.     else {
  517.       g_writech (row, col, *s, c, page);
  518.       col++;
  519.     }
  520.     s++;
  521.   }
  522. }
  523.  
  524. /* get information about physical graphics device */
  525.  
  526. void g_info(p)
  527. struct g_info *p;
  528. {
  529.   p->card     = g_card;
  530.   p->display  = g_display;
  531.   p->xsize    = g_xsize;
  532.   p->ysize    = g_ysize;
  533.   p->colormax = g_colormax;
  534.   p->pages    = g_pages;
  535.   p->curpage  = g_curpage;
  536.   p->xchsize  = g_xchsize;
  537.   p->ychsize  = g_ychsize;
  538. }
  539.