home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / turtlegr.zip / scm / turtlegr.c < prev   
C/C++ Source or Header  |  1992-10-27  |  42KB  |  1,303 lines

  1.  
  2. /*      file    turtlegr.c                              *
  3.  *      Copyright (C) 1992      sjm@ee.tut.fi           *
  4.  *                              jtl@cc.tut.fi           *
  5.  *                                                      *
  6.  *      Turtlegraphics primitives for the               *
  7.  *      SCM interpreter by Aubrey Jaffer                *
  8.  *                                                      *
  9.  *      Last modification: 13.10.1992                   *
  10.  *                                                      *
  11.  *      Versions:                                       *
  12.  *      12.3.1992       The first version.              *
  13.  *      13.3.1992       Added the possibility to pass   *
  14.  *                      floating point args.            *
  15.  *      15.3.1992       Graphics cards other than EGA   *
  16.  *                      are now supported.              *
  17.  *      9.4.1992        The internal representation     *
  18.  *                      of X & Y is now float.          *
  19.  *      13.10.1992      Added X11 support.              *
  20.  *                      A major rewrite of certain      *
  21.  *                      parts.                          *
  22.  *                      Put -DX11 -DFLOATS to CFLAGS    *
  23.  *                      in Makefile to get it.          *
  24.  *                                                      *
  25.  *      REMEMBER to define INITS=init_turtlegr()        *
  26.  *      in the Makefile.                                *
  27.  *                                                      */
  28.  
  29. /*                                                                      *
  30.  *       This code tries to compromise between two very different       *
  31.  *      systems: MSDOS and UNIX with the X11 windowing system.          *
  32.  *      The MSDOS version was build first and it really shows.  :)      *
  33.  *      The X port is a partial rewrite of the old MSDOS stuff          *
  34.  *      and plays around with #ifdef's a lot.  The result is,           *
  35.  *      eventually, a C source which is expected to compile             *
  36.  *      under both MSDOS and UNIX (X11).                                *
  37.  *       The X code handles colors emulating CGA palette. It tries      *
  38.  *      to act sensibly even on a monochrome screen and when the        *
  39.  *      color palette is full.                                          *
  40.  *       X event handling is implemented with polling whenever          *
  41.  *      appropriate. This is not The Right Way to do it in X, but       *
  42.  *      it was easiest to adopt in this case.                           *
  43.  *       Another solution would have been to make the X graphics        *
  44.  *      a separate process, but I didn't want to because I wanted       *
  45.  *      to keep it simple. I can't tell how good an example of porting  *
  46.  *      MSDOS software to X this is, but it works.                      *
  47.  *                                                                      *
  48.  *       This has been tested with SunOs 4.1.2 with X11R5, Linux 0.98.1 *
  49.  *      with Xfree86 1.1 (X11R5 port) and in MSDOS with BC 3.1.         *
  50.  *      Because the code uses only the basic Xlib calls, it should      *
  51.  *      compile without problems under _any_ UNIX with X11R4 or newer.  *
  52.  *                                                                      *
  53.  *      Please send bugreports to sjm@ee.tut.fi.                        *
  54.  *      I'm especially interested in hearing about ports to other       *
  55.  *      platforms than those tested by me.                              *
  56.  *                                                                      *
  57.  *      - sjm                                                           *
  58.  *                                                                      */
  59.  
  60.  
  61. /****************************************************/
  62. /*****  GENERIC includes & defines              *****/
  63. /****************************************************/
  64. #include        "scm.h"         /* includes config.h as well    */
  65. #include        "patchlvl.h"    /* Guess...                     */
  66. #include        <math.h>        /* sin(), cos(), fmod()         */
  67. #include    <stdlib.h>    /* atexit()            */
  68.  
  69. /****************************************************/
  70. /*****  X11 specific includes & defines         *****/
  71. /****************************************************/
  72. #ifdef X11
  73.  
  74. /* Xlib include files */
  75. #include <X11/Xlib.h>
  76. #include <X11/Xutil.h>
  77. #include <X11/Xatom.h>
  78. #include <stdio.h>
  79.  
  80. #include "turtle"
  81. #define BITMAPDEPTH 1
  82.  
  83. #define PROGNAME        "scm"
  84. #define CLASSNAME       "Scm"
  85. #define WINDOWNAME      "TurtleSCM graphics window"
  86. #define ICONNAME        "TurtleSCM"
  87.  
  88. #define GR_MAX_XSIZE    1024
  89. #define GR_MAX_YSIZE    1024
  90. #define GR_DEF_XSIZE    640
  91. #define GR_DEF_YSIZE    480
  92. #define GR_MIN_XSIZE    64
  93. #define GR_MIN_YSIZE    64
  94.  
  95. /* Fake CGA colormap with X - yuk!                              */
  96. #define GR_COLORS       16              /* CGA/EGA counterpart  */
  97. #define GR_COLOR00      "black"         /* black                */
  98. #define GR_COLOR01      "blue2"         /* blue                 */
  99. #define GR_COLOR02      "green2"        /* green                */
  100. #define GR_COLOR03      "cyan2"         /* cyan                 */
  101. #define GR_COLOR04      "red3"          /* red                  */
  102. #define GR_COLOR05      "magenta2"      /* magenta              */
  103. #define GR_COLOR06      "yellow2"       /* brown                */
  104. #define GR_COLOR07      "light gray"    /* white                */
  105. #define GR_COLOR08      "gray"          /* gray                 */
  106. #define GR_COLOR09      "blue1"         /* light blue           */
  107. #define GR_COLOR10      "green1"        /* light green          */
  108. #define GR_COLOR11      "cyan1"         /* light cyan           */
  109. #define GR_COLOR12      "red1"          /* light red            */
  110. #define GR_COLOR13      "magenta1"      /* light magenta        */
  111. #define GR_COLOR14      "yellow1"       /* yellow               */
  112. #define GR_COLOR15      "white"         /* bright white         */
  113.  
  114. #ifdef  __STDC__
  115. static void     gr_events( int );
  116. #else
  117. static void     gr_events();
  118. #endif
  119.  
  120. #else
  121. /****************************************************/
  122. /*****  PC specific includes & defines          *****/
  123. /****************************************************/
  124. #include        <graphics.h>
  125. #include        <stdlib.h>      /* for getenv()                 */
  126. #include        <stdio.h>       /* for fputs()                  */
  127. #define         BGIDIR_ENVSTRING        "BGIDIR"
  128. #endif
  129.  
  130. /********************************************/
  131. /***** GENERIC code, declarations       *****/
  132. /********************************************/
  133. #define         SIN( x )                \
  134.                 sin( ((x)/180.0) * M_PI )
  135. #define         COS( x )                \
  136.                 cos( ((x)/180.0) * M_PI )
  137.  
  138. static  int             gr_graphicsavail = 0;
  139. static  int             gr_grmode_on = 0;
  140. static  float           gr_dir = 0.0;
  141. static  int             gr_max_x=0, gr_max_y=0, gr_max_color=0;
  142. static  float           gr_x=0.0, gr_y=0.0;
  143. static  int             gr_color = 0;
  144.  
  145. static  char    s_gr_draw[]             = "draw";
  146. static  char    s_gr_move[]             = "move";
  147. static  char    s_gr_setcolor[]         = "set-color!";
  148. static  char    s_gr_turnright[]        = "turn-right";
  149. static  char    s_gr_turnleft[]         = "turn-left";
  150. static  char    s_gr_turnto[]           = "turn-to!";
  151.  
  152. static  char    s_gr_getdot[]           = "get-dot";
  153. static  char    s_gr_drawTo[]           = "draw-to!";
  154. static  char    s_gr_drawto[]           = "draw-to";
  155. static  char    s_gr_moveTo[]           = "move-to!";
  156.  
  157. static  char    s_gr_setdot[]           = "set-dot!";
  158. static  char    s_gr_validXYC[]         = "valid-xyc?";
  159.  
  160. #ifdef __GNUC__
  161. inline
  162. #else
  163. static
  164. #endif
  165. int      valid_XYC( x, y, color )
  166. int     x, y, color;
  167. {
  168. #ifdef X11
  169.         /* Check for changed window size */
  170.         gr_events(0);
  171. #endif
  172.         if( (x <= gr_max_x) && (y <= gr_max_y) && (color <= gr_max_color)
  173.             && (x >= 0) && (y >= 0) && (color >= 0) )
  174.                 return( 1 );
  175.         else
  176.                 return( 0 );
  177. } /* valid_XYC() */
  178.  
  179.  
  180. /********************************************************************/
  181. /*****  X11 specific variable and function declarations         *****/
  182. /********************************************************************/
  183. #ifdef X11
  184. static Display          *gr_display;            /* The X display        */
  185. static int              gr_screen;              /* The X screen number  */
  186. static Window           gr_win;                 /* The drawable Window  */
  187. static GC               gr_gc;                  /* Graphics Context     */
  188. static unsigned long    gr_colortbl[GR_COLORS]; /* Color table          */
  189. static XEvent           gr_event;               /* Event structure      */
  190.  
  191. /* These are needed for XSetWMProperties */
  192. static char     *gr_windowname  = WINDOWNAME;
  193. static char     *gr_iconname    = ICONNAME;
  194. static char     gr_progname[]   = PROGNAME;
  195. static char     gr_classname[]  = CLASSNAME;
  196. static int      gr_argc         = 1;
  197. static char     *gr_argv[]      = { gr_progname, NULL };
  198.  
  199. static void     gr_eventhandler( event )
  200. XEvent          event;
  201. {
  202.           switch( event.type ) {
  203.  
  204.           case ConfigureNotify:
  205. #ifdef TESTING
  206.             fputs( "Received ConfigureNotify event\n", stderr );
  207. #endif
  208.             gr_max_x = event.xconfigure.width - 1;
  209.             gr_max_y = event.xconfigure.height - 1;
  210.             break;
  211.  
  212.           case MapNotify:
  213. #ifdef TESTING
  214.             fputs( "Received MapNotify event\n", stderr );
  215. #endif
  216.             break;
  217.  
  218.           case DestroyNotify:
  219. #ifdef TESTING
  220.             fputs( "Received DestroyNotify event\n", stderr );
  221. #endif
  222.             break;
  223.  
  224.           case UnmapNotify:
  225. #ifdef TESTING
  226.             fputs( "Received UnmapNotify event\n", stderr );
  227. #endif
  228.             break;
  229.  
  230.           case Expose:
  231. #ifdef TESTING
  232.             fputs( "Received Expose event\n", stderr );
  233. #endif
  234.             if( event.xexpose.count != 0 )
  235.               break;
  236.             break;
  237.  
  238.           case ClientMessage:
  239. #ifdef TESTING
  240.             fputs( "Received ClientMessage event\n", stderr );
  241. #endif
  242.             break;
  243.  
  244.           default:
  245.             /* Throw away any unknown events */
  246.             break;
  247.  
  248.           } /* switch */
  249. }
  250.  
  251. static void     gr_events( expected )
  252. int             expected;
  253. {
  254. int             i;
  255.  
  256.         /* Get at least 'expected' events */
  257.         for( i = 0; i < expected; ++i ) {
  258.           XNextEvent( gr_display, &gr_event );
  259.           gr_eventhandler( gr_event );
  260.         }
  261.         /* Handle all remaining events if there are any */
  262.         /* XPending will call XFlush() if it doesn't find events at once */
  263.         while( XPending(gr_display) ) {
  264.           XNextEvent( gr_display, &gr_event );
  265.           gr_eventhandler( gr_event );
  266.         } /* while */
  267. } /* gr_events() */
  268.  
  269. static void     gr_typedevent( type )
  270. int             type;
  271. {
  272.         do {
  273.           XNextEvent( gr_display, &gr_event );
  274.           gr_eventhandler( gr_event );
  275.         } while( gr_event.type != type );
  276.         /* Handle all remaining events if there are any */
  277.         /* XPending will call XFlush() if it doesn't find events at once */
  278.         while( XPending(gr_display) ) {
  279.           XNextEvent( gr_display, &gr_event );
  280.           gr_eventhandler( gr_event );
  281.         } /* while */
  282. }
  283.  
  284.  
  285. /********************************************************************/
  286. /*****  PC specific variable and function declarations          *****/
  287. /********************************************************************/
  288. #else
  289.  
  290. static  int             gr_max_display_mode;
  291. static  int             gr_drivernum;
  292.  
  293. #endif
  294.  
  295.  
  296. /********************************************************************/
  297. /********************************************************************/
  298. /***    User callable SCM routines begin here           ***
  299.  ***                                                    ***
  300.  ***                                                    ***/
  301.  
  302.  
  303. SCM     gr_helpgr()
  304. {
  305.         fputs( "\
  306. Ret   Name               nargs    args        returns\n\
  307. ---------------------------------------------------------\n\
  308. B  graphics-avail?         0       -          #t if graphics available\n\
  309. B  graphics-mode!          0       -          #f if no graphics\n\
  310. B  text-mode!              0       -          #t on success\n\
  311. B  clear-graphics!         0       -          #f if not in graphics mode\n\
  312. i  max-x                   0       -          maximum value of x\n\
  313. i  max-y                   0       -          maximum value of y\n\
  314. i  max-color               0       -          maximum value of color\n\
  315. B  valid-xyc?              3       x y color  #t if valid\n\
  316. B  set-dot!                3       x y color  #t on success\n\
  317. i  get-dot                 2       x y        color of the dot in (x,y)\n\
  318.                                               or #f if (x,y) not legal\n\
  319. \n\
  320. NOTE: Origin (0,0) is in the upper left corner.\n\n\
  321. ", stdout );
  322.         return  BOOL_T;
  323. } /* gr_helpgr() */
  324.  
  325.  
  326. SCM     gr_helpturtlegr()
  327. {
  328.         fputs( "\
  329. Ret   Name               nargs    args        returns\n\
  330. ---------------------------------------------------------\n\
  331. B  goto-home!              0       -          #f if not in graphics mode\n\
  332. B  goto-center!            0       -          #f if not in graphics mode\n\
  333. B  goto-nw!                0       -          #f if not in graphics mode\n\
  334. B  goto-ne!                0       -          #f if not in graphics mode\n\
  335. B  goto-sw!                0       -          #f if not in graphics mode\n\
  336. B  goto-se!                0       -          #f if not in graphics mode\n\
  337. B  draw                    1       length     #t if target within drawing area\n\
  338. B  draw-to                 2       x y        #t if (x,y) within drawing area\n\
  339. B  draw-to!                2       x y        #t if (x,y) within drawing area\n\
  340. B  move                    1       length     #t if target within drawing area\n\
  341. B  move-to!                2       x y        #t if (x,y) within drawing area\n\
  342. i  where-x                 0       -          current x-coordinate\n\
  343. i  where-y                 0       -          current y-coordinate\n\
  344. i  turn-right              1       angle      drawing direction in degrees\n\
  345. i  turn-left               1       angle      drawing direction in degrees\n\
  346. i  turn-to!                1       angle      drawing direction in degrees\n\
  347. i  what-direction          0       -          drawing direction in degrees\n\
  348. B  set-color!              1       color      #t if color valid\n\
  349. i  what-color              0       -          current drawing color\n\n\
  350. ", stdout );
  351.         return  BOOL_T;
  352. } /* gr_helpturtlegr() */
  353.  
  354.  
  355. SCM     gr_available()
  356. {
  357.         if( gr_graphicsavail )
  358.                 return  BOOL_T;
  359.         else
  360.                 return  BOOL_F;
  361. } /* gr_available() */
  362.  
  363.  
  364. SCM     gr_maxx()
  365. {
  366.         if( !gr_grmode_on )
  367.                 return  BOOL_F;
  368. #ifdef X11
  369.         /* Check for changed window size */
  370.         gr_events(0);
  371. #endif
  372.         return  MAKINUM( (long)gr_max_x );
  373. } /* gr_maxx() */
  374.  
  375.  
  376. SCM     gr_maxy()
  377. {
  378.         if( !gr_grmode_on )
  379.                 return  BOOL_F;
  380. #ifdef X11
  381.         /* Check for changed window size */
  382.         gr_events(0);
  383. #endif
  384.         return  MAKINUM( (long)gr_max_y );
  385. } /* gr_maxy() */
  386.  
  387. SCM     gr_maxc()
  388. {
  389.         if( !gr_grmode_on )
  390.                 return  BOOL_F;
  391.         return  MAKINUM( (long)gr_max_color );
  392. } /* gr_maxc() */
  393.  
  394.  
  395. SCM     gr_validXYC( x, y, c )
  396. SCM     x, y, c;
  397. {
  398. int     xi, yi, ci;
  399.  
  400.         ASSERT( NUMBERP(x),x,ARG1,s_gr_validXYC );
  401.         ASSERT( NUMBERP(y),y,ARG2,s_gr_validXYC );
  402.         ASSERT( NUMBERP(c),c,ARG3,s_gr_validXYC );
  403.         if( !gr_grmode_on )
  404.                 return  BOOL_F;
  405.  
  406.         if( INUMP(x) )
  407.                 xi = (int)(INUM(x));
  408.         else
  409.                 xi = (int)(REALPART(x));
  410.  
  411.         if( INUMP(y) )
  412.                 yi = (int)(INUM(y));
  413.         else
  414.                 yi = (int)(REALPART(y));
  415.  
  416.         if( INUMP(c) )
  417.                 ci = (int)(INUM(c));
  418.         else
  419.                 ci = (int)(REALPART(c));
  420.  
  421. /* valid_XYC() calls gr_events() */
  422.  
  423.         if( valid_XYC( xi, yi, ci ) )
  424.                 return  BOOL_T;
  425.         else
  426.                 return  BOOL_F;
  427. } /* gr_validXYC() */
  428.  
  429.  
  430. SCM     gr_grmode()
  431. {
  432.         if( !gr_graphicsavail )
  433.                 return  BOOL_F;
  434. #ifdef  X11
  435.         /* bwuah... but it works :) */
  436.         if( !gr_grmode_on ) {
  437.             XMapWindow( gr_display, gr_win );
  438.             gr_typedevent( MapNotify );
  439.         }
  440. #else   /* PC version */
  441.         setgraphmode( gr_max_display_mode );
  442. #endif
  443.         gr_grmode_on = 1;
  444.         return  BOOL_T;
  445. } /* gr_grmode() */
  446.  
  447. SCM     gr_txtmode()
  448. {
  449.         if( !gr_graphicsavail )
  450.                 return  BOOL_F;
  451. #ifdef  X11
  452.         /* bwuah... but it works :) */
  453.         if( gr_grmode_on ) {
  454.             XUnmapWindow( gr_display, gr_win );
  455.             gr_typedevent( UnmapNotify );
  456.         }
  457. #else   /* PC version */
  458.         restorecrtmode();
  459. #endif
  460.         gr_grmode_on = 0;
  461.         return  BOOL_T;
  462. } /* gr_txtmode() */
  463.  
  464.  
  465. SCM     gr_cleargraph()
  466. {
  467.         if( !gr_grmode_on )
  468.                 return  BOOL_F;
  469. #ifdef  X11
  470.         XClearWindow( gr_display, gr_win );
  471.         gr_events(0);
  472. #else   /* PC version */
  473.         cleardevice();
  474. #endif
  475.         return  BOOL_T;
  476. } /* gr_cleargraph() */
  477.  
  478.  
  479. SCM     gr_setdot( x, y, c )
  480. SCM     x, y, c;
  481. {
  482. int     xi, yi, ci;
  483.  
  484.         ASSERT( NUMBERP(x),x,ARG1,s_gr_setdot );
  485.         ASSERT( NUMBERP(y),y,ARG2,s_gr_setdot );
  486.         ASSERT( NUMBERP(c),c,ARG3,s_gr_setdot );
  487.         if( !gr_grmode_on )
  488.                 return  BOOL_F;
  489.  
  490.         if( INUMP(x) )
  491.                 xi = (int)(INUM(x));
  492.         else
  493.                 xi = (int)(REALPART(x));
  494.  
  495.         if( INUMP(y) )
  496.                 yi = (int)(INUM(y));
  497.         else
  498.                 yi = (int)(REALPART(y));
  499.  
  500.         if( INUMP(c) )
  501.                 ci = (int)(INUM(c));
  502.         else
  503.                 ci = (int)(REALPART(c));
  504. #ifdef TESTING
  505.         fprintf( stderr, "set-dot! called (%d,%d,%d)\n", xi, yi, ci );
  506. #endif
  507.         if( !valid_XYC( xi, yi, ci ) )
  508.                 return  BOOL_F;
  509. #ifdef  X11
  510.         /* Set the drawing color */
  511.         XSetForeground( gr_display, gr_gc, gr_colortbl[ ci ] );
  512.         XDrawPoint( gr_display, gr_win, gr_gc, xi, yi );
  513.         /* Restore the drawing color */
  514.         XSetForeground( gr_display, gr_gc, gr_colortbl[ gr_color ] );
  515.         gr_events(0);
  516. #else   /* PC version */
  517.         putpixel( xi, yi, ci );
  518. #endif
  519.         return  BOOL_T;
  520. } /* gr_setdot() */
  521.  
  522.  
  523. SCM     gr_getdot( x, y )
  524. SCM     x, y;
  525. {
  526. int                     xi, yi;
  527. #ifdef  X11
  528. XImage                  *xim;
  529. XWindowAttributes       wattr;
  530. unsigned long           dot;
  531. int                     i;
  532. #endif
  533.         ASSERT( NUMBERP(x),x,ARG1,s_gr_getdot );
  534.         ASSERT( NUMBERP(y),y,ARG2,s_gr_getdot );
  535.         if( !gr_grmode_on )
  536.                 return  BOOL_F;
  537.         if( INUMP(x) )
  538.                 xi = (int)(INUM(x));
  539.         else
  540.                 xi = (int)(REALPART(x));
  541.  
  542.         if( INUMP(y) )
  543.                 yi = (int)(INUM(y));
  544.         else
  545.                 yi = (int)(REALPART(y));
  546. #ifdef TESTING
  547.         fprintf( stderr, "get-dot called (%d,%d)\n", xi, yi );
  548. #endif
  549.         if( !valid_XYC( xi, yi, 0 ) )
  550.                 return  BOOL_F;
  551. #ifdef  X11
  552.         /* Now, this IS ugly. But it's there if you need it.            */
  553.  
  554.         /* Have to make sure that the window is mapped.  Tough...       */
  555.         XGetWindowAttributes( gr_display, gr_win, &wattr );
  556.         if( wattr.map_state == IsUnmapped ) {
  557.             XMapWindow( gr_display, gr_win );
  558.             gr_typedevent( MapNotify );
  559.         }
  560.         /* I KNOW this sucks.                                           */
  561.         xim = XGetImage( gr_display,gr_win, xi,yi, 1,1, AllPlanes, XYPixmap );
  562.         dot = XGetPixel( xim, 0,0 );
  563.         for( i = 0; i < GR_COLORS; ++i ) {
  564.             if( gr_colortbl[i] == dot )
  565.                 return MAKINUM( (long)i );
  566.         }
  567.         /* This should never happen. There's garbage in the window!     */
  568.         fprintf( stderr, "%s: %s: Got an illegal pixel value %lu. \
  569. Is there garbage?\n", gr_progname, s_gr_getdot, dot );
  570.         return BOOL_F;
  571. #else   /* PC version */
  572.         return MAKINUM( (long)getpixel( xi, yi ) );
  573. #endif
  574. } /* gr_getdot() */
  575.  
  576. SCM     gr_draw( S )
  577. SCM     S;
  578. {
  579. float   xf, yf;
  580. float   sf;
  581. int     ok;
  582.  
  583.         ASSERT( NUMBERP(S),S,ARG1,s_gr_draw );
  584.         if( !gr_grmode_on )
  585.                 return  BOOL_F;
  586.         if( INUMP(S) )
  587.                 sf = (float)(INUM(S));
  588.         else
  589.                 sf = REALPART(S);
  590. #ifdef TESTING
  591.         fprintf( stderr, "draw called (%f)\n", sf );
  592. #endif
  593.         ok = 1;
  594.         xf = gr_x + ( COS( gr_dir ) * sf );
  595.         yf = gr_y + ( SIN( gr_dir ) * sf );
  596.         if( (int)xf > gr_max_x ) {
  597.                 xf = (float)gr_max_x;
  598.                 ok = 0;
  599.         }
  600.         else if( xf < 0.0 ) {
  601.                 xf = 0.0;
  602.                 ok = 0;
  603.         }
  604.         if( (int)yf > gr_max_y ) {
  605.                 yf = (float)gr_max_y;
  606.                 ok = 0;
  607.         }
  608.         else if( yf < 0.0 ) {
  609.                 yf = 0.0;
  610.                 ok = 0;
  611.         }
  612. #ifdef  X11
  613.         XDrawLine( gr_display, gr_win, gr_gc,
  614.                    (int)gr_x,(int)gr_y,
  615.                    (int)xf,(int)yf );
  616.         gr_events(0);
  617. #else   /* PC version */
  618.         line( (int)gr_x,(int)gr_y, (int)xf,(int)yf );
  619. #endif
  620.         gr_x = xf;
  621.         gr_y = yf;
  622.         if( ok )
  623.                 return  BOOL_T;
  624.         else
  625.                 return  BOOL_F;
  626. } /* gr_draw() */
  627.  
  628.  
  629. SCM     gr_move( S )
  630. SCM     S;
  631. {
  632. float   xf, yf;
  633. float   sf;
  634. int     ok;
  635.  
  636.         ASSERT( NUMBERP(S),S,ARG1,s_gr_move );
  637.         if( !gr_grmode_on )
  638.                 return  BOOL_F;
  639.         if( INUMP(S) )
  640.                 sf = (float)(INUM(S));
  641.         else
  642.                 sf = REALPART(S);
  643. #ifdef TESTING
  644.         fprintf( stderr, "move called (%f)\n", sf );
  645. #endif
  646.         ok = 1;
  647.         xf = gr_x + ( COS( gr_dir ) * sf );
  648.         yf = gr_y + ( SIN( gr_dir ) * sf );
  649.  
  650.         if( (int)xf > gr_max_x ) {
  651.                 xf = (float)gr_max_x;
  652.                 ok = 0;
  653.         }
  654.         else if( xf < 0.0 ) {
  655.                 xf = 0.0;
  656.                 ok = 0;
  657.         }
  658.         if( (int)yf > gr_max_y ) {
  659.                 yf = (float)gr_max_y;
  660.                 ok = 0;
  661.         }
  662.         else if( yf < 0.0 ) {
  663.                 yf = 0.0;
  664.                 ok = 0;
  665.         }
  666.         gr_x = xf;
  667.         gr_y = yf;
  668.         if( ok )
  669.                 return  BOOL_T;
  670.         else
  671.                 return  BOOL_F;
  672. } /* gr_move() */
  673.  
  674.  
  675. SCM     gr_drawto( x, y )
  676. SCM     x, y;
  677. {
  678. int     xi, yi;
  679.  
  680.         ASSERT( NUMBERP(x),x,ARG1,s_gr_drawto );
  681.         ASSERT( NUMBERP(y),y,ARG2,s_gr_drawto );
  682.         if( !gr_grmode_on )
  683.                 return  BOOL_F;
  684.         if( INUMP(x) )
  685.                 xi = (int)(INUM(x));
  686.         else
  687.                 xi = (int)(REALPART(x));
  688.  
  689.         if( INUMP(y) )
  690.                 yi = (int)(INUM(y));
  691.         else
  692.                 yi = (int)(REALPART(y));
  693. #ifdef TESTING
  694.         fprintf( stderr, "draw-to called (%d,%d)\n", xi, yi );
  695. #endif
  696.         if( !valid_XYC( xi,yi, 0 ) )
  697.                 return  BOOL_F;
  698. #ifdef  X11
  699.         XDrawLine( gr_display, gr_win, gr_gc,
  700.                    (int)gr_x,(int)gr_y, xi,yi );
  701.         gr_events(0);
  702. #else   /* PC version */
  703.         line( (int)gr_x,(int)gr_y, xi,yi );
  704. #endif
  705.         return  BOOL_T;
  706. } /* gr_drawto() */
  707.  
  708.  
  709. SCM     gr_drawTo( x, y )
  710. SCM     x, y;
  711. {
  712. float   xf, yf;
  713.  
  714.         ASSERT( NUMBERP(x),x,ARG1,s_gr_drawTo );
  715.         ASSERT( NUMBERP(y),y,ARG2,s_gr_drawTo );
  716.         if( !gr_grmode_on )
  717.                 return  BOOL_F;
  718.         if( INUMP(x) )
  719.                 xf = (float)(INUM(x));
  720.         else
  721.                 xf = (REALPART(x));
  722.  
  723.         if( INUMP(y) )
  724.                 yf = (float)(INUM(y));
  725.         else
  726.                 yf = (REALPART(y));
  727. #ifdef TESTING
  728.         fprintf( stderr, "draw-to! called (%d,%d)\n", (int)xf, (int)yf );
  729. #endif
  730.         if( !valid_XYC( (int)xf,(int)yf, 0 ) )
  731.                 return  BOOL_F;
  732. #ifdef  X11
  733.         XDrawLine( gr_display, gr_win, gr_gc,
  734.                    (int)gr_x,(int)gr_y,
  735.                    (int)xf,(int)yf );
  736.         gr_events(0);
  737. #else   /* PC version */
  738.         line( (int)gr_x,(int)gr_y, (int)xf,(int)yf );
  739. #endif
  740.         gr_x = xf;
  741.         gr_y = yf;
  742.         return  BOOL_T;
  743. } /* gr_drawTo() */
  744.  
  745.  
  746. SCM     gr_moveTo( x, y )
  747. SCM     x, y;
  748. {
  749. float   xf, yf;
  750.  
  751.         ASSERT( NUMBERP(x),x,ARG1,s_gr_moveTo );
  752.         ASSERT( NUMBERP(y),y,ARG2,s_gr_moveTo );
  753.         if( !gr_grmode_on )
  754.                 return  BOOL_F;
  755.         if( INUMP(x) )
  756.                 xf = (float)(INUM(x));
  757.         else
  758.                 xf = (REALPART(x));
  759.  
  760.         if( INUMP(y) )
  761.                 yf = (float)(INUM(y));
  762.         else
  763.                 yf = (REALPART(y));
  764. #ifdef TESTING
  765.         fprintf( stderr, "move-to! called (%d,%d)\n", (int)xf, (int)yf );
  766. #endif
  767.         if( !valid_XYC( (int)xf,(int)yf, 0 ) )
  768.                 return  BOOL_F;
  769.         gr_x = xf;
  770.         gr_y = yf;
  771.         return  BOOL_T;
  772. } /* gr_moveTo() */
  773.  
  774.  
  775. SCM     gr_setcolor( c )
  776. SCM     c;
  777. {
  778. int     color;
  779.  
  780.         ASSERT( NUMBERP(c),c,ARG1,s_gr_setcolor );
  781.         if( !gr_grmode_on )
  782.                 return  BOOL_F;
  783.         if( INUMP(c) )
  784.                 color = (int)(INUM(c));
  785.         else
  786.                 color = (int)(REALPART(c));
  787. #ifdef TESTING
  788.         fprintf( stderr, "set-color! called (%d)\n", color );
  789. #endif
  790.         if( !valid_XYC( 0,0, color ) )
  791.                 return  BOOL_F;
  792.         gr_color = color;
  793. #ifdef  X11
  794.         /* Set the drawing color */
  795.         XSetForeground( gr_display, gr_gc, gr_colortbl[ gr_color ] );
  796.         gr_events(0);
  797. #else   /* PC version */
  798.         setcolor( gr_color );
  799. #endif
  800.         return  BOOL_T;
  801. } /* gr_setcolor() */
  802.  
  803.  
  804. SCM     gr_turnright( d )
  805. SCM     d;
  806. {
  807. float   df;
  808.  
  809.         ASSERT( NUMBERP(d),d,ARG1,s_gr_turnright );
  810.         if( !gr_grmode_on )
  811.                 return  BOOL_F;
  812.         if( INUMP(d) )
  813.                 df = (float)(INUM(d));
  814.         else
  815.                 df = REALPART(d);
  816.         df = fmod( df, 360.0 );
  817.         gr_dir -= df;
  818.         gr_dir = fmod( gr_dir, 360.0 );
  819.         return MAKINUM( (long)(gr_dir+.5) );
  820. } /* gr_turnright() */
  821.  
  822.  
  823. SCM     gr_turnleft( d )
  824. SCM     d;
  825. {
  826. float   df;
  827.  
  828.         ASSERT( NUMBERP(d),d,ARG1,s_gr_turnleft );
  829.         if( !gr_grmode_on )
  830.                 return  BOOL_F;
  831.         if( INUMP(d) )
  832.                 df = (float)(INUM(d));
  833.         else
  834.                 df = REALPART(d);
  835.         df = fmod( df, 360.0 );
  836.         gr_dir += df;
  837.         gr_dir = fmod( gr_dir, 360.0 );
  838.         return MAKINUM( (long)(gr_dir+.5) );
  839. } /* gr_turnleft() */
  840.  
  841.  
  842. SCM     gr_turnto( d )
  843. SCM     d;
  844. {
  845. float   df;
  846.  
  847.         ASSERT( NUMBERP(d),d,ARG1,s_gr_turnto );
  848.         if( !gr_grmode_on )
  849.                 return  BOOL_F;
  850.         if( INUMP(d) )
  851.                 df = (float)(INUM(d));
  852.         else
  853.                 df = REALPART(d);
  854.         df = fmod( df, 360.0 );
  855.         gr_dir = df;
  856.         return MAKINUM( (long)(gr_dir+.5) );
  857. } /* gr_turnto() */
  858.  
  859.  
  860. SCM     gr_gotohome()
  861. {
  862.         if( !gr_grmode_on )
  863.                 return  BOOL_F;
  864.         gr_x = gr_y = 0.0;
  865.         return  BOOL_T;
  866. } /* gr_gotohome() */
  867.  
  868.  
  869. SCM     gr_gotocenter()
  870. {
  871.         if( !gr_grmode_on )
  872.                 return  BOOL_F;
  873. #ifdef X11
  874.         /* Check for changed window size */
  875.         gr_events(0);
  876. #endif
  877.         gr_x = ((float)gr_max_x+1.0) / 2.0;
  878.         gr_y = ((float)gr_max_y+1.0) / 2.0;
  879.         return  BOOL_T;
  880. } /* gr_gotocenter() */
  881.  
  882.  
  883. SCM     gr_gotonw()
  884. {
  885.         if( !gr_grmode_on )
  886.                 return  BOOL_F;
  887. #ifdef X11
  888.         /* Check for changed window size */
  889.         gr_events(0);
  890. #endif
  891.         gr_x = 0.0;
  892.         gr_y = 0.0;
  893.         return  BOOL_T;
  894. } /* gr_gotonw() */
  895.  
  896.  
  897. SCM     gr_gotosw()
  898. {
  899.         if( !gr_grmode_on )
  900.                 return  BOOL_F;
  901. #ifdef X11
  902.         /* Check for changed window size */
  903.         gr_events(0);
  904. #endif
  905.         gr_x = 0.0;
  906.         gr_y = (float)gr_max_y;
  907.         return  BOOL_T;
  908. } /* gr_gotosw() */
  909.  
  910.  
  911. SCM     gr_gotone()
  912. {
  913.         if( !gr_grmode_on )
  914.                 return  BOOL_F;
  915. #ifdef X11
  916.         /* Check for changed window size */
  917.         gr_events(0);
  918. #endif
  919.         gr_x = (float)gr_max_x;
  920.         gr_y = 0.0;
  921.         return  BOOL_T;
  922. } /* gr_gotone() */
  923.  
  924.  
  925. SCM     gr_gotose()
  926. {
  927.         if( !gr_grmode_on )
  928.                 return  BOOL_F;
  929. #ifdef X11
  930.         /* Check for changed window size */
  931.         gr_events(0);
  932. #endif
  933.         gr_x = (float)gr_max_x;
  934.         gr_y = (float)gr_max_y;
  935.         return  BOOL_T;
  936. } /* gr_gotose() */
  937.  
  938.  
  939. SCM     gr_whatcolor()
  940. {
  941.         if( !gr_grmode_on )
  942.                 return  BOOL_F;
  943.         return  MAKINUM( (long)gr_color );
  944. } /* gr_whatcolor() */
  945.  
  946.  
  947. SCM     gr_whatdirection()
  948. {
  949.         if( !gr_grmode_on )
  950.                 return  BOOL_F;
  951.         return  MAKINUM( (long)(gr_dir+.5) );
  952. } /* gr_whatdirection() */
  953.  
  954.  
  955. SCM     gr_wherex()
  956. {
  957.         if( !gr_grmode_on )
  958.                 return  BOOL_F;
  959.         return  MAKINUM( (long)gr_x );
  960. } /* gr_wherex() */
  961.  
  962.  
  963. SCM     gr_wherey()
  964. {
  965.         if( !gr_grmode_on )
  966.                 return  BOOL_F;
  967.         return  MAKINUM( (long)gr_y );
  968. } /* gr_wherey() */
  969.  
  970.  
  971. static iproc    graph0[] = {
  972.                 { "help-gr", gr_helpgr },
  973.                 { "help-turtlegr", gr_helpturtlegr },
  974.                 { "graphics-mode!", gr_grmode },
  975.                 { "text-mode!", gr_txtmode },
  976.                 { "clear-graphics!", gr_cleargraph },
  977.                 { "graphics-avail?", gr_available },
  978.                 { "max-x", gr_maxx },
  979.                 { "max-y", gr_maxy },
  980.                 { "max-color", gr_maxc },
  981.                 { "what-color", gr_whatcolor },
  982.                 { "what-direction", gr_whatdirection },
  983.                 { "where-x", gr_wherex },
  984.                 { "where-y", gr_wherey },
  985.                 { "goto-home!", gr_gotohome },
  986.                 { "goto-center!", gr_gotocenter },
  987.                 { "goto-nw!", gr_gotonw },
  988.                 { "goto-sw!", gr_gotosw },
  989.                 { "goto-ne!", gr_gotone },
  990.                 { "goto-se!", gr_gotose },
  991.                 {0,0}
  992.         };
  993.  
  994. static iproc    graph1[] = {
  995.                 { s_gr_draw, gr_draw },
  996.                 { s_gr_move, gr_move },
  997.                 { s_gr_setcolor, gr_setcolor },
  998.                 { s_gr_turnright, gr_turnright },
  999.                 { s_gr_turnleft, gr_turnleft },
  1000.                 { s_gr_turnto, gr_turnto },
  1001.                 {0,0}
  1002.         };
  1003.  
  1004. static iproc    graph2[] = {
  1005.                 { s_gr_getdot, gr_getdot },
  1006.                 { s_gr_drawTo, gr_drawTo },
  1007.                 { s_gr_drawto, gr_drawto },
  1008.                 { s_gr_moveTo, gr_moveTo },
  1009.                 {0,0}
  1010.         };
  1011.  
  1012. static iproc    graph3[] = {
  1013.                 { s_gr_setdot, gr_setdot },
  1014.                 { s_gr_validXYC, gr_validXYC },
  1015.                 {0,0}
  1016.         };
  1017.  
  1018. #if defined __STDC__ || defined __TURBOC__
  1019. void    close_turtlegr()
  1020. {
  1021. #ifdef  X11
  1022.         gr_events(0);
  1023.         XFreeColors( gr_display, DefaultColormap(gr_display,gr_screen),
  1024.                      gr_colortbl, GR_COLORS, AllPlanes );
  1025.         XFreeGC( gr_display, gr_gc );
  1026.         XUnmapWindow( gr_display, gr_win );
  1027.         XDestroyWindow( gr_display, gr_win );
  1028. #else   /* PC version */
  1029.         closegraph();
  1030. #endif
  1031. } /* close_turtlegr() */
  1032. #endif
  1033.  
  1034. void    init_turtlegr() /* detects if graphics is available; must be
  1035.                            called among program initializations */
  1036. {
  1037. #ifdef  X11
  1038.   char                  *display_name = NULL;   /* Server to connect to      */
  1039.   Pixmap                icon_pixmap;            /* Icon                      */
  1040.   XSizeHints            size_hints;             /* Preferred sizes           */
  1041.   XSetWindowAttributes  win_attribs;            /* Window attributes         */
  1042.   XWMHints              wm_hints;               /* Window manager hints      */
  1043.   XClassHint            class_hints;            /* Class hints               */
  1044.   XTextProperty         window_name, icon_name; /* Names for Icon & Window   */
  1045.   XGCValues             gc_values;              /* Graphics Context values   */
  1046.   static char           *colorname[GR_COLORS] = {
  1047.                                 GR_COLOR00, GR_COLOR01, GR_COLOR02, GR_COLOR03,
  1048.                                 GR_COLOR04, GR_COLOR05, GR_COLOR06, GR_COLOR07,
  1049.                                 GR_COLOR08, GR_COLOR09, GR_COLOR10, GR_COLOR11,
  1050.                                 GR_COLOR12, GR_COLOR13, GR_COLOR14, GR_COLOR15
  1051.                         };
  1052.   XColor                x_color;                /* X11 Color structure       */
  1053.   unsigned long         mask;                   /* Mask for selections       */
  1054.   int                   i;                      /* loop counter variable     */
  1055.  
  1056. #else   /* PC version */
  1057. int     errcode;
  1058. #endif
  1059.  
  1060. /***************************/
  1061. /* generic initializations */
  1062. /***************************/
  1063.   gr_x = gr_y = gr_dir = 0.0;
  1064.   gr_max_x = gr_max_y = gr_max_color = 0;
  1065.  
  1066.   gr_graphicsavail = 0; /* DEFAULT is no graphics - you can do without */
  1067.  
  1068. /********************************************/
  1069. /*****  Initialize X11 turtlegraphics   *****/
  1070. /********************************************/
  1071. #ifdef X11
  1072.         /* connect to X server */
  1073.         if( (gr_display = XOpenDisplay(display_name)) != NULL )
  1074.         {
  1075.  
  1076.           /*****************************/
  1077.           /* connection to X server OK */
  1078.           /*****************************/
  1079.  
  1080.           gr_screen = DefaultScreen( gr_display );      /* X screen number */
  1081.  
  1082.           /* Create a window with Black background and border */
  1083.           gr_win
  1084.             = XCreateSimpleWindow( gr_display,
  1085.                                   RootWindow( gr_display, gr_screen),
  1086.                                   0, 0, /* initial placement */
  1087.                                   GR_DEF_XSIZE, GR_DEF_YSIZE,
  1088.                                   3, /* border width */
  1089.                                   /* border pixel value */
  1090.                                   BlackPixel(gr_display,gr_screen),
  1091.                                   /* background pixel value */
  1092.                                   BlackPixel(gr_display,gr_screen) );
  1093.  
  1094.           /* Select input (events) for the window */
  1095.           XSelectInput( gr_display, gr_win,
  1096.                         StructureNotifyMask|ExposureMask );
  1097.  
  1098.           /* Check for backing store capability */
  1099.           if( !DoesBackingStore(DefaultScreenOfDisplay(gr_display)) )
  1100.           {
  1101.             fprintf( stderr, "%s: Warning: \
  1102. X server does not offer backing store capability.\n\
  1103. Window cannot be redrawn if obscured. Sorry...\n", gr_progname );
  1104.           }
  1105.           else
  1106.           {
  1107.               /* Enable the backing store feature of X server
  1108.                  and set bit gravity */
  1109.               win_attribs.bit_gravity   = NorthWestGravity;
  1110.               win_attribs.backing_store = Always;
  1111.               mask                      = CWBitGravity | CWBackingStore;
  1112.               XChangeWindowAttributes( gr_display, gr_win, mask, &win_attribs );
  1113.           }
  1114.  
  1115.           /* Make names of Window and Icon for window manager */
  1116.           if( XStringListToTextProperty(&gr_windowname,1,&window_name) == 0 ) {
  1117.             (void)fprintf( stderr, "%s: Structure allocation for windowName\
  1118.  failed.\n", gr_progname );
  1119.             exit( 42 );
  1120.           }
  1121.           if( XStringListToTextProperty(&gr_iconname,1,&icon_name) == 0 ) {
  1122.             (void)fprintf( stderr, "%s: Structure allocation for iconName\
  1123.  failed.\n", gr_progname );
  1124.             exit( 42 );
  1125.           }
  1126.  
  1127.           /* Create the icon */
  1128.           icon_pixmap = XCreateBitmapFromData( gr_display, gr_win, turtle_bits,
  1129.                                                turtle_width, turtle_height );
  1130.  
  1131.           /* Window size, state, icon etc. hints for the window manager */
  1132.           size_hints.flags = PPosition | PMaxSize | PMinSize | USSize;
  1133.           /* position and desired size are given to XCreateSimpleWindow call */
  1134.           size_hints.min_width          = GR_MIN_XSIZE;
  1135.           size_hints.min_height         = GR_MIN_YSIZE;
  1136.           size_hints.max_width          = GR_MAX_XSIZE;
  1137.           size_hints.max_height         = GR_MAX_YSIZE;
  1138.           wm_hints.flags = StateHint | IconPixmapHint | InputHint;
  1139.           wm_hints.initial_state        = NormalState;
  1140.           wm_hints.input                = False;
  1141.           wm_hints.icon_pixmap          = icon_pixmap;
  1142.           class_hints.res_name          = gr_progname;
  1143.           class_hints.res_class         = gr_classname;
  1144.           XSetWMProperties( gr_display, gr_win, &window_name, &icon_name,
  1145.                             gr_argv, gr_argc,
  1146.                             &size_hints, &wm_hints, &class_hints );
  1147.  
  1148.  
  1149.           /* Handle colors; this is quite complicated in X11 */
  1150.  
  1151.           if( DefaultDepth( gr_display, gr_screen ) == 1 )
  1152.           {
  1153.             /* Only 1 bitplane, BW screen */
  1154.             /* Emulate colors with 0 as Black and 1-15 White */
  1155.             gr_colortbl[0] = BlackPixel( gr_display, gr_screen );
  1156.             for( i = 1; i < GR_COLORS; ++i )
  1157.               gr_colortbl[i] = WhitePixel( gr_display, gr_screen );
  1158. #ifdef TESTING
  1159.             fprintf( stderr, "%s: 1-plane system, substituting White for \
  1160. colors 1-15.\n", gr_progname );
  1161.             fprintf( stderr, "%s: Pixel value is %lu for Black, \
  1162. %lu for White\n", gr_progname, gr_colortbl[0], gr_colortbl[1] );
  1163. #endif
  1164.           }
  1165.           else
  1166.           {
  1167.               /* more than 1 bitplane */
  1168.               for( i = 0; i < GR_COLORS; ++i )
  1169.               {
  1170.                   /* Initialize the colortable using named colors */
  1171.                   if( XParseColor( gr_display,
  1172.                                    DefaultColormap(gr_display,gr_screen),
  1173.                                    colorname[ i ], &x_color ) )
  1174.                   {
  1175.                       if( !XAllocColor( gr_display,
  1176.                                         DefaultColormap(gr_display,gr_screen),
  1177.                                         &x_color ) )
  1178.                       {
  1179.                           fprintf( stderr, "%s: Can't allocate color \
  1180. \"%s\" (%d). Substituting White.\n",
  1181.                                    gr_progname,
  1182.                                    colorname[ i ], i );
  1183.                           gr_colortbl[i] = WhitePixel( gr_display, gr_screen );
  1184.                       }
  1185.                       else
  1186.                       {
  1187.                           /* succeeded in allocating color */
  1188.                           gr_colortbl[ i ] = x_color.pixel;
  1189. #ifdef TESTING
  1190.                           fprintf( stderr, "%s: Pixel value is %lu for %s.\n",
  1191.                                    gr_progname, gr_colortbl[i], colorname[i] );
  1192. #endif
  1193.                       }
  1194.                   }
  1195.                   else
  1196.                   {
  1197.                       /* could not parse color */
  1198.                       fprintf( stderr,
  1199.                                "%s: Color name \"%s\" (%d) not in database. \
  1200. Substituting White.\n",
  1201.                                gr_progname, colorname[i], i );
  1202.                       gr_colortbl[i] = WhitePixel( gr_display, gr_screen );
  1203.                   }
  1204.               } /* for */
  1205.           } /* else */
  1206.           gr_max_color = GR_COLORS - 1;
  1207.  
  1208.           /* Create and initialize a default GC */
  1209.           gr_gc = XCreateGC( gr_display, gr_win, 0L, &gc_values );
  1210.  
  1211.           /* Initialize the drawing color, default's black */
  1212.           XSetForeground( gr_display, gr_gc, gr_colortbl[ 0 ] );
  1213.           XSetBackground( gr_display, gr_gc, gr_colortbl[ 0 ] );
  1214.           gr_color = 0;
  1215.  
  1216.           /* OK, we _do_ have graphics available */
  1217.           gr_graphicsavail = 1;
  1218.  
  1219. #ifdef __STDC__
  1220.           /* Let's do the Right Thing if possible :) */
  1221.           atexit( close_turtlegr );
  1222. #endif
  1223.       } /* if */
  1224.       else {
  1225.           gr_graphicsavail = 0;
  1226.       }
  1227. /********************************************/
  1228. /*****  Initialize PC turtlegraphics    *****/
  1229. /********************************************/
  1230. #else   /* PC version */
  1231.           gr_drivernum = DETECT;
  1232.  
  1233.           detectgraph( &gr_drivernum, &gr_max_display_mode );
  1234.           if( gr_drivernum != grNotDetected ) {
  1235.               if( !getenv( BGIDIR_ENVSTRING ) )
  1236.                  fprintf( stderr,
  1237.                         "You really should set the %s environment variable.\n",
  1238.                         BGIDIR_ENVSTRING );
  1239.               initgraph( &gr_drivernum, &gr_max_display_mode,
  1240.                          getenv( BGIDIR_ENVSTRING ) );
  1241.               errcode = graphresult();
  1242.               if( errcode != grOk ) {
  1243.                   fputs( "Graphics error: ", stderr );
  1244.                   fputs( grapherrormsg( errcode ), stderr );
  1245.                   exit( 1 );
  1246.               }
  1247.               moveto( 0,0 );
  1248.               gr_x = gr_y = 0.0;
  1249.               setcolor( 0 );
  1250.               gr_color = 0;
  1251.               gr_max_x = getmaxx();
  1252.               gr_max_y = getmaxy();
  1253.               gr_max_color = getmaxcolor();
  1254.               gr_max_display_mode = getmaxmode();
  1255.               restorecrtmode();
  1256.               gr_graphicsavail = 1;
  1257.               atexit( close_turtlegr );
  1258.           }
  1259.           else {
  1260.               gr_graphicsavail = 0;
  1261.           }
  1262. #endif
  1263.  
  1264. /* generic */
  1265.         init_iprocs( graph0, tc7_subr_0 );
  1266.         init_iprocs( graph1, tc7_subr_1 );
  1267.         init_iprocs( graph2, tc7_subr_2 );
  1268.         init_iprocs( graph3, tc7_subr_3 );
  1269.         gr_grmode_on = 0;
  1270.  
  1271. #ifndef X11
  1272.   /* PC version clears screen so this must be repeated */
  1273.   fputs("SCM version ",stdout);
  1274.   fputs(SCMVERSION,stdout);
  1275.   intprint((long)PATCHLEVEL,10,stdout);
  1276.   puts(", Copyright (C) 1990, 1991, 1992 Aubrey Jaffer.\n\
  1277. SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.\n\
  1278. This is free software, and you are welcome to redistribute it\n\
  1279. under certain conditions; type `(terms)' for details.");
  1280. #endif
  1281.  
  1282.   puts( "\nSCM Turtlegraphics Copyright (C) 1992 sjm@cc.tut.fi, jtl@cc.tut.fi\n\
  1283. Type `(help-gr)' or `(help-turtlegr)' for a quick reference of\n\
  1284. the new primitives.\n" );
  1285.  
  1286.   if( !gr_graphicsavail ) {
  1287. #ifdef X11
  1288.         fprintf( stderr, "%s: No X server found. \
  1289. Turtlegraphics not available.\n", gr_progname );
  1290. #else
  1291.         fputs( "No graphics adapter detected. \
  1292. Turtlegraphics not available.\n", stderr );
  1293. #endif
  1294.   }
  1295.   else {
  1296. #ifdef X11
  1297.         gr_events(0);
  1298. #else
  1299.         ;
  1300. #endif
  1301.   }
  1302. } /* init_turtlegr() */
  1303.