home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Graphics / SPD / Sources / drv_ibm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-10  |  9.9 KB  |  475 lines  |  [TEXT/R*ch]

  1. /*
  2.  * Modified: 7 Sep 1993
  3.  *           Antonio [acc] Costa
  4.  *           Added support to GRX graphics
  5.  *             If less than 256 colors, use only black & white.
  6.  *             Define GRX to have GRX graphics
  7.  *
  8.  * Modified: 17 Mar 1993
  9.  *           Eduard [esp] Schwan
  10.  *           Passed bg_color to display_init
  11.  *             (unfortunate side-effect is you should now call
  12.  *             lib_output_background_color BEFORE lib_output_viewpoint.
  13.  *             This may not be the best approach - please review!)
  14.  */
  15.  
  16. #include <dos.h>
  17. #include <io.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. /* Note that if you use Borland/Turbo C++, you need "<mem.h>" in addition to
  21.    <stdlib.h>.  Why they put their allocation routines there I don't know. */
  22. #include "drv.h"
  23.  
  24. #if defined( __GNUC__ )
  25. #include <pc.h>
  26.  
  27. #ifdef GRX
  28. #include "grx.h"
  29. #else
  30. #define MK_FP(seg, ofs) ((void *)(0xE0000000 + ((seg)<<4) + ofs))
  31. #define FP_OFF(ptr) (unsigned short)(ptr)
  32. #define FP_SEG(ptr) (unsigned short)(((unsigned long)ptr >> 16) & 0x0FFF)
  33. #define segread(x) (void)(x)
  34. #endif
  35. #define getch() getkey()
  36. #define _far
  37. #else
  38. #include <conio.h>
  39. #endif
  40.  
  41. /* Scaling factors to make an image fit onto the screen */
  42. static float X_Display_Scale = 1.0;
  43. static float Y_Display_Scale = 1.0;
  44.  
  45. int maxx = 320;
  46. int maxy = 200;
  47.  
  48. static COORD3 bkgnd_color;
  49.  
  50. #ifndef GRX
  51. typedef unsigned char pallette_array[256][3];
  52. pallette_array *pallette = NULL;
  53.  
  54. /* Use the PC's BIOS to set a video mode. */
  55. static void
  56. setvideomode(int mode)
  57. {
  58.     union REGS reg;
  59.     reg.h.ah = 0;
  60.     reg.h.al = mode;
  61.     int86(0x10, ®, ®);
  62. }
  63.  
  64. /* Use the PC's BIOS to set a pixel on the screen */
  65. static void
  66. biospixel(unsigned x, unsigned y, unsigned char val)
  67. {
  68.     union REGS reg;
  69.     reg.h.ah = 0x0c;
  70.     reg.h.al = val;
  71.     reg.x.cx = x;
  72.     reg.x.dx = y;
  73.     int86(0x10, ®, ®);
  74. }
  75.  
  76. /* Set a 256 entry pallette with the values given in "palbuf". */
  77. static void
  78. setmany(unsigned char palbuf[256][3], int start, int count)
  79. {
  80.     unsigned char _far *fp;
  81.     union REGS regs;
  82.     struct SREGS sregs;
  83.     unsigned i;
  84.  
  85. #if defined( __GNUC__ )
  86.     /* This should work for most compilers - only tested with GNU C++, so
  87.        it isn't turned on for anything else */
  88.     for (i=start;i<start+count;i++) {
  89.     regs.x.ax = 0x1010;
  90.     regs.x.bx = i;
  91.     regs.h.ch = palbuf[i][1];
  92.     regs.h.cl = palbuf[i][2];
  93.     regs.h.dh = palbuf[i][0];
  94.     int86x(0x10, ®s, ®s, &sregs);
  95.     return;
  96.     }
  97. #elif defined( DOS386 )
  98.     /* Put the contents of the new palette into real memory, the only
  99.        place I know that won't impact things is the video RAM. */
  100.     fp = MK_FP(_x386_zero_base_selector, 0xA0000);
  101. #else
  102.     /* If you aren't using GNU C++ or Zortech C++ for 386 protected mode,
  103.        then you need to use a compiler that supports access to all of the
  104.        registers, including ES, to be able to set the pallette all at once. */
  105.     fp = MK_FP(0xA000, 0);
  106. #endif
  107.  
  108.     /* If you got here then you are using Zortech C++ */
  109.     for (i=start;i<start+count;i++) {
  110.     fp[3*(i-start)  ] = palbuf[i][0];
  111.     fp[3*(i-start)+1] = palbuf[i][1];
  112.     fp[3*(i-start)+2] = palbuf[i][2];
  113.     }
  114.  
  115.     regs.x.ax = 0x1012;
  116.     regs.x.bx = start;
  117.     regs.x.cx = count;
  118.     regs.x.dx = 0;
  119.     segread(&sregs);
  120.     sregs.es  = 0xA000;
  121. #if defined( DOS386 )
  122.     int86x_real(0x10, ®s, ®s, &sregs);
  123. #else
  124.     int86x(0x10, ®s, ®s, &sregs);
  125. #endif
  126.     /* Now clear off the values that got dumped into the video RAM */
  127.     for (i=0;i<3*count; i++)
  128.     *fp++ = 0;
  129. }
  130. #endif
  131.  
  132. /* Make space for a pallette & make a 332 color map, if possible */
  133. static void
  134. pallette_init()
  135. {
  136.     unsigned i, r, g, b;
  137.  
  138. #ifdef GRX
  139.     if (GrNumColors() != 256) {
  140.      GrSetColor(0, 0, 0, 0);
  141.      GrSetColor(1, 255, 255, 255);
  142.      return;
  143.     }
  144. #else
  145.     if (pallette == NULL) {
  146.     pallette = malloc(sizeof(pallette_array));
  147.     if (pallette == NULL) {
  148.         fprintf(stderr, "Failed to allocate pallette array\n");
  149.         exit(1);
  150.     }
  151.     }
  152. #endif
  153.  
  154.     i = 0;
  155.     for (r=0;r<8;r++)
  156.     for (g=0;g<8;g++)
  157.         for (b=0;b<4;b++) {
  158. #ifdef GRX
  159.         GrSetColor(i, r << 5, g << 5, b << 6);
  160. #else
  161.         (*pallette)[i][0] = r << 3;
  162.         (*pallette)[i][1] = g << 3;
  163.         (*pallette)[i][2] = b << 4;
  164. #endif
  165.         i++;
  166.         }
  167. #ifndef GRX
  168.     setmany(*pallette, 0, 256);
  169. #endif
  170. }
  171.  
  172. /* Turn a RGB color defined as <0, 0, 0> -> <1, 1, 1> into a color that
  173.    is in a 332 pallette, if possible */
  174. static int
  175. determine_color_index(color)
  176.     COORD3 color;
  177. {
  178.     int i;
  179.     unsigned char r, g, b;
  180.  
  181. #ifdef GRX
  182.     if (GrNumColors() != 256)
  183.     return 1;
  184. #endif
  185.  
  186.     i = 255.0 * color[Z];
  187.     if (i<0) i=0;
  188.     else if (i>=256) i = 255;
  189.     b = (unsigned char)i;
  190.  
  191.     i = 255.0 * color[Y];
  192.     if (i<0) i=0;
  193.     else if (i>=256) i = 255;
  194.     g = (unsigned char)i;
  195.  
  196.     i = 255.0 * color[X];
  197.     if (i<0) i=0;
  198.     else if (i>=256) i = 255;
  199.     r = (unsigned char)i;
  200.  
  201.     return (r & 0xE0) | ((g & 0xE0) >> 3) | (b >> 6);
  202. }
  203.  
  204. static void
  205. plotpoint(int x, int y, unsigned char color)
  206. {
  207. #ifdef GRX
  208.     GrPlotNC(x, y, color);
  209. #else
  210.     unsigned char _far *fp;
  211.  
  212. #if defined( _WINDOWS )
  213. #elif defined( DOS386 )
  214.     fp = MK_FP(_x386_zero_base_selector, 0xA0000 + 320 * y + x);
  215. #else
  216.     fp = MK_FP(0xA000, 320 * y + x);
  217. #endif
  218.     *fp = color;
  219. #endif
  220. }
  221.  
  222. /* Draw a line between two points - if you have a better one available
  223.    from your compiler, then replace this thing - it's not fast. */
  224. static void
  225. line2d(int x1, int y1, int x2, int y2, int color_index)
  226. {
  227. #ifdef GRX
  228.     if (x1 == x2)
  229.     GrVLineNC(x1, y1, y2, color_index);
  230.     else if (y1 == y2)
  231.     GrHLineNC(x1, x2, y1, color_index);
  232.     else
  233.     GrLineNC(x1, y1, x2, y2, color_index);
  234. #else
  235.     int d1, x, y;
  236.     int ax, ay;
  237.     int sx, sy;
  238.     int dx, dy;
  239.  
  240.     dx = x2 - x1;
  241.     ax = ABSOLUTE(dx) << 1;
  242.     sx = SGN(dx);
  243.     dy = y2 - y1;
  244.     ay = ABSOLUTE(dy) << 1;
  245.     sy = SGN(dy);
  246.  
  247.     x = x1;
  248.     y = y1;
  249.  
  250.     plotpoint(x, y, color_index);
  251.     if (ax > ay) {
  252.     /* x dominant */
  253.     d1 = ay - (ax >> 1);
  254.     for (;;) {
  255.         if (x==x2) return;
  256.         if (d1>=0) {
  257.         y += sy;
  258.         d1 -= ax;
  259.         }
  260.         x += sx;
  261.         d1 += ay;
  262.         plotpoint(x, y, color_index);
  263.     }
  264.     }
  265.     else {
  266.     /* y dominant */
  267.     d1 = ax - (ay >> 1);
  268.     for (;;) {
  269.         if (y == y2) return;
  270.         if (d1 >= 0) {
  271.         x += sx;
  272.         d1 -= ay;
  273.         }
  274.         y += sy;
  275.         d1 += ax;
  276.         plotpoint(x, y, color_index);
  277.     }
  278.     }
  279. #endif
  280. }
  281.  
  282. void
  283. display_clear(void)
  284. {
  285. #ifdef GRX
  286.     GrClearScreen(0);
  287. #else
  288.     unsigned _far *fp;
  289.     unsigned i;
  290.  
  291.     /* Proposal: Use "bkgnd_color" to clear screen? [esp] */
  292.  
  293. #if defined( _WINDOWS )
  294.     /* For windows you need to make a region and do a clear, currently
  295.        there isn't anything written for that. */
  296. #elif defined( DOS386 )
  297.     /* An unsigned is 4 bytes, so we can clear the screen twice as fast */
  298.     fp = MK_FP(_x386_zero_base_selector, 0xA0000);
  299.     for (i=0;i<16000; i++)
  300.     *fp++ = 0;
  301. #elif defined( __GNUC__ )
  302.     fp = MK_FP(0xA000, 0);
  303.     for (i=0;i<16000; i++)
  304.     *fp++ = 0;
  305. #else
  306.     /* An unsigned is only 2 bytes */
  307.     fp = MK_FP(0xA000, 0);
  308.     for (i=0;i<32000; i++)
  309.     *fp++ = 0;
  310. #endif
  311. #endif
  312. }
  313.  
  314. void
  315. display_init(xres, yres, bk_color)
  316.     int xres, yres;
  317.     COORD3 bk_color;
  318. {
  319.     static int init_flag = 0;
  320.     COORD3 white;
  321.  
  322.     /* remember the background color */
  323.     COPY_COORD3(bkgnd_color, bk_color);
  324.  
  325.     if (init_flag) {
  326.     display_clear();
  327.     return;
  328.     }
  329.     else
  330.        init_flag = 1;
  331.  
  332. #ifdef GRX
  333.     GrSetMode(GR_default_graphics);
  334.     maxx = GrSizeX();
  335.     maxy = GrSizeY();
  336. #else
  337.     /* Turn on the 320x200 VGA mode & set the pallette */
  338.     setvideomode(19);
  339.     maxx = 320;
  340.     maxy = 200;
  341. #endif
  342.  
  343.     pallette_init();
  344.  
  345.     if (xres > maxx)
  346.     X_Display_Scale = (float)maxx / (float)xres;
  347.     else
  348.     X_Display_Scale = 1.0;
  349.     if (yres > maxy)
  350.     Y_Display_Scale = (float)maxy / (float)yres;
  351.     else
  352.     Y_Display_Scale = 1.0;
  353.     if (X_Display_Scale < Y_Display_Scale)
  354.     Y_Display_Scale = X_Display_Scale;
  355.     else if (Y_Display_Scale < X_Display_Scale)
  356.     X_Display_Scale = Y_Display_Scale;
  357.  
  358.     /* Outline the actual "visible" display area in the window */
  359.     SET_COORD3(white, 1, 1, 1);
  360.     if (X_Display_Scale == 1.0) {
  361.     display_line(-xres/2, -yres/2, -xres/2, yres/2, white);
  362.     display_line( xres/2, -yres/2,  xres/2, yres/2, white);
  363.     }
  364.     if (Y_Display_Scale == 1.0) {
  365.     display_line(-xres/2,  yres/2,  xres/2,  yres/2, white);
  366.     display_line(-xres/2, -yres/2,  xres/2, -yres/2, white);
  367.     }
  368. }
  369.  
  370. void
  371. display_close(int wait_flag)
  372. {
  373. #ifndef GRX
  374.     union REGS regs;
  375. #endif
  376.  
  377.     if (wait_flag) {
  378. #if !defined( _WINDOWS )
  379.     while (!kbhit()) ;
  380. #endif
  381.     if (!getch()) getch();
  382.     }
  383. #ifndef GRX
  384.     if (pallette != NULL)
  385.     free(pallette);
  386. #endif
  387.  
  388.     /* Go back to standard text mode */
  389. #ifdef GRX
  390.     GrSetMode(GR_default_text);
  391. #else
  392.     regs.x.ax = 0x0003;
  393.     int86(0x10, ®s, ®s);
  394. #endif
  395.  
  396.     return;
  397. }
  398.  
  399. void
  400. display_plot(x, y, color)
  401.     int x, y;
  402.     COORD3 color;
  403. {
  404.     double xt, yt;
  405.  
  406.     yt = maxy/2 - Y_Display_Scale * y;
  407.     xt = maxx/2 + X_Display_Scale * x;
  408.  
  409.     /* Make sure the point is in the display */
  410.     if (xt < 0.0) x = 0;
  411.     else if (xt > maxx) x = maxx;
  412.     else x = (int)xt;
  413.     if (yt < 0.0) y = 0;
  414.     else if (yt > maxy) y = maxy;
  415.     else y = (int)yt;
  416.  
  417.     plotpoint(x, y, determine_color_index(color));
  418. }
  419.  
  420. void
  421. display_line(x0, y0, x1, y1, color)
  422.     int x0, y0, x1, y1;
  423.     COORD3 color;
  424. {
  425.     float xt, yt;
  426.  
  427. #if !defined( _WINDOWS )
  428.     if (kbhit())
  429.     {
  430.       if (!getch())
  431.     getch();
  432.       display_close(0);
  433.       exit(1);
  434.     }
  435. #endif
  436.  
  437.     /* Scale from image size to actual screen pixel size */
  438.     yt = maxy/2 - Y_Display_Scale * y0;
  439.     xt = maxx/2 + X_Display_Scale * x0;
  440.  
  441.     if (xt < 0.0)
  442.     x0 = 0;
  443.     else if (xt > maxx) {
  444.     x0 = maxx - 1;
  445.     }
  446.     else x0 = (int)xt;
  447.     if (yt < 0.0)
  448.     y0 = 0;
  449.     else if (yt > maxy) {
  450.     y0 = maxy;
  451.     }
  452.     else
  453.     y0 = (int)yt;
  454.  
  455.     /* Scale from image size to actual screen pixel size */
  456.     yt = maxy/2 - Y_Display_Scale * y1;
  457.     xt = maxx/2 + X_Display_Scale * x1;
  458.  
  459.     if (xt < 0.0)
  460.     x1 = 0;
  461.     else if (xt > maxx) {
  462.     x1 = maxx - 1;
  463.     }
  464.     else x1 = (int)xt;
  465.     if (yt < 0.0)
  466.     y1 = 0;
  467.     else if (yt > maxy) {
  468.     y1 = maxy;
  469.     }
  470.     else
  471.     y1 = (int)yt;
  472.  
  473.     line2d(x0, y0, x1, y1, determine_color_index(color));
  474. }
  475.