home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / c / msc51 / example / grdemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  20.4 KB  |  925 lines

  1. /*
  2.     GRDEMO.C - Demonstrates capabilities of the QuickC graphics library
  3.  
  4.     Since this program uses functions not found in the QuickC core
  5.     library or the graphics library, you must use a program list to
  6.     compile in memory. Select Set Program List from the File menu
  7.     and enter GRDEMO as the program list name. Then specify GRDEMO
  8.     as the only entry in the program list.
  9.  
  10.     An alternative is to create a quick library containing the routines
  11.     used in GRDEMO. Use the following lines to build the quick library
  12.     and load it into QuickC:
  13.  
  14.         QLIB /s grdemo.c
  15.         QC /l grdemo.qlb grdemo
  16.  */
  17.  
  18. #include <graph.h>
  19. #include <string.h>
  20. #include <math.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <conio.h>
  24. #include <time.h>
  25. #include <bios.h>
  26.  
  27. /* Functions - prototypes and macros */
  28.  
  29. /* Demo functions */
  30.  
  31. int main(void);
  32.  
  33.     /* Demo selections */
  34. void circles(void);
  35. void sphere(void);
  36. int polygons(void);
  37. int spiral(int angle, int inc);
  38. int inspiral(int side, int angle, int inc);
  39. void adjust(void);
  40.  
  41.     /* Menus */
  42. int menu(int row, int col, char * *items);
  43. void box(int row, int col, int hi, int wid);
  44. void itemize(int row, int col, char *str, int len);
  45.  
  46.     /* Color changes */
  47. int nextatrib(int init);
  48. void nextcolor(void);
  49.  
  50. /* Turtle graphics routines */
  51.  
  52.     /* Initiate and    set defaults */
  53. short setturtle(short mode);
  54. void home(void);
  55.  
  56.     /* Control pen and color */
  57. int pendown(int state);
  58. short fillstate(short state);
  59. short penatrib(short atrib);
  60. short borderatrib(short border);
  61.  
  62.     /* Control angle */
  63. short turn(short angle);
  64. short turnto(short angle);
  65.  
  66.     /* Turtle movement */
  67. short move(short distance);
  68. short moveto(short x,short y);
  69. short poly(short number,short side);
  70.  
  71.     /* Figures (defined as macros) */
  72.  
  73. /* Puts a circle with radius <r> at current location.
  74.    Returns nonzero if successful. */
  75. #define circle(r) _ellipse(tc.isFill, \
  76.     tc.xCur-(r), adj(tc.yCur-(r)), tc.xCur+(r), adj(tc.yCur+(r)))
  77.  
  78. /* Puts an ellipse with width <w> and height <h> at current location.
  79.    Returns nonzero if successful. */
  80. #define ellipse(w,h) _ellipse(tc.isFill, tc.xCur-((w)/2), \
  81.     adj(tc.yCur-((h)/2)), tc.xCur+((w)/2), adj(tc.yCur+((h)/2)))
  82.  
  83.     /* Miscellaneous */
  84.  
  85. /* Fills starting at the current location.
  86.    Returns nonzero if successful. */
  87. #define fillin() _floodfill(tc.xCur, adj(tc.yCur),tc.border)
  88.  
  89. /* Returns nonzero if the current location is onscreen. */
  90. #define onscreen() (!((tc.xCur < -xMAX) || (tc.xCur > xMAX) || \
  91.               (tc.yCur < -yMAX) || (tc.yCur > yMAX)))
  92.  
  93. /* Returns a long int mixed from red <r>, green <g>, and blue <b> bytes. */
  94. #define RGB(r,g,b) (((long) ((b) << 8 | (g)) << 8) | (r))
  95.  
  96. short adj(short y);
  97. unsigned cursor(unsigned value);
  98.  
  99. /* Constants */
  100.  
  101. #define    xMAX    (tc.xCnt / 2)
  102. #define    yMAX    (tc.yCnt / 2)
  103. #define    CIRCUMFERENCE        360
  104. #define HALFCIRCUMFERENCE   180
  105.  
  106. #define    PI    3.141593
  107. #define    DEFAULT    -1
  108. #define    TRUE    1
  109. #define    FALSE    0
  110. #define TCURSOROFF  0x2020
  111. #define LASTATR 15
  112. #define NLASTATR 14
  113.  
  114. /* Scan codes */
  115.  
  116. #define UP      72
  117. #define    DOWN    80
  118. #define    LEFT    75
  119. #define    RIGHT    77
  120. #define    ENTER    28
  121.  
  122. /* Structures for configuration    and other data */
  123. struct videoconfig vc;
  124.  
  125. struct {
  126.     long    xUnits,    yUnits;
  127.     short    xCnt, yCnt;
  128.     short   xCur, yCur;
  129.     short    angle;
  130.     short   border;
  131.     short   numAtribs;
  132.     short   numColors;
  133.     short   atrib;
  134.     short   isPen;
  135.     short   isFill;
  136. } tc = { 125L, 90L };      /* Initial values for aspect.
  137.                Change to adjust for your screen. */
  138.  
  139. /* Initial and work arrays for remapable colors. */
  140.  
  141. long iColors[] = {
  142.     _BLACK,         _BLUE,          _GREEN,         _CYAN,
  143.     _RED,           _MAGENTA,       _BROWN,         _WHITE,
  144.     _GRAY,          _LIGHTBLUE,     _LIGHTGREEN,    _LIGHTCYAN,
  145.     _LIGHTRED,      _LIGHTMAGENTA,  _LIGHTYELLOW,   _BRIGHTWHITE };
  146.  
  147. long wColors[256];
  148.  
  149. /* Array and enum for main menu */
  150.  
  151. char *mnuMain[]    = {
  152.     "Quit",
  153.     "Circles",
  154.     "Sphere",
  155.     "Tunnel",
  156.     "Spiral",
  157.     "Inverted Spiral",
  158.     "Adjust Aspect",
  159.     "Change Mode",
  160.     NULL };
  161.  
  162. /* Define constants 0 to 7 (equivalent to multiple #define statements) */
  163.  
  164. enum choice { QUIT, CIRCLES, SPHERE, TUNNEL, SPIRAL,
  165.               INSPIRAL, ADJUST, CHANGE };
  166.  
  167. /* Arrays for video modes */
  168.  
  169. char *mnuModes[] = {
  170.     "MRES4COLOR ",
  171.     "MRESNOCOLOR",
  172.     "HRESBW",
  173.     "MRES16COLOR",
  174.     "HRES16COLOR",
  175.     "ERESCOLOR",
  176.     "VRES2COLOR",
  177.     "VRES16COLOR",
  178.     "MRES256COLOR",
  179.     NULL };
  180.  
  181. /* Array for modes */
  182. int modes[] = {
  183.     _MRES4COLOR,
  184.     _MRESNOCOLOR,
  185.     _HRESBW,
  186.     _MRES16COLOR,
  187.     _HRES16COLOR,
  188.     _ERESCOLOR,
  189.     _VRES2COLOR,
  190.     _VRES16COLOR,
  191.     _MRES256COLOR,
  192.     _ERESNOCOLOR,
  193.     _HERCMONO,
  194.     DEFAULT    };
  195.  
  196. /* Structure for menu attributes (variables for color and monochrome) */
  197. struct mnuAtr {
  198.     int    fgNormal, fgSelect, fgBorder;
  199.     long    bgNormal, bgSelect, bgBorder;
  200.     int     centered;
  201.     char    nw[2], ne[2], se[2], sw[2], ns[2], ew[2];
  202. };
  203.  
  204. struct mnuAtr menus = {
  205.     0x00, 0x0f, 0x04,
  206.     0x03, 0x04, 0x03,
  207.     TRUE,
  208.     "┌", "┐", "┘", "└", "│", "─"
  209. };
  210.  
  211. struct mnuAtr bwmenus = {
  212.         0x07, 0x00, 0x07,
  213.         0x00, 0x07, 0x00,
  214.     TRUE,
  215.     "┌", "┐", "┘", "└", "│", "─"
  216. };
  217.  
  218. char mess1[] = { "Graphics Demonstration Program" } ;
  219. char mess2[] = { "Move to menu selection with cursor keys" };
  220. char mess3[] = { "Press ENTER to select" };
  221. int lmess1 = sizeof(mess1), lmess2 = sizeof(mess2), lmess3 = sizeof(mess3);
  222.  
  223. main ()
  224. {
  225.     int choice, crow, ccol;
  226.     int vmode;
  227.  
  228.     _setvideomode (_DEFAULTMODE);
  229.     _getvideoconfig(&vc);
  230.     crow = vc.numtextrows / 2;
  231.     ccol = vc.numtextcols /    2;
  232.  
  233.     /* Select best text and    graphics modes and adjust menus    */
  234.  
  235.     switch (vc.adapter) {
  236.         case _MDPA :
  237.             puts("No graphics mode available.\n");
  238.             exit(0);
  239.         case _CGA :
  240.             mnuModes[3] = NULL;
  241.             vmode =    _MRES4COLOR;
  242.             break;
  243.         case _HGC :
  244.             mnuModes[6] = NULL;
  245.             vmode = _HERCMONO;
  246.             break;
  247.         case _EGA :
  248.             mnuModes[6] = NULL;
  249.             if (vc.memory > 64)
  250.                 vmode = _ERESCOLOR;
  251.             else
  252.                 vmode = _HRES16COLOR;
  253.             break;
  254.         case _VGA :
  255.         case _MCGA :
  256.             vmode =    _MRES256COLOR;
  257.             break;
  258.     }
  259.     switch (vc.mode) {
  260.         case _TEXTBW80 :
  261.         case _TEXTBW40 :
  262.             menus = bwmenus;
  263.             break;
  264.         case _TEXTMONO :
  265.         case _ERESNOCOLOR :
  266.         case _HERCMONO :
  267.             menus =    bwmenus;
  268.             if (vmode != _HERCMONO)
  269.                 vmode = _ERESNOCOLOR;
  270.             mnuMain[7] = NULL;
  271.     }
  272.  
  273.     srand((unsigned)time(0L));
  274.  
  275.     _settextposition(1,ccol - (lmess1 / 2));
  276.     _outtext(mess1);
  277.     _settextposition(2,ccol - (lmess2 / 2));
  278.     _outtext(mess2);
  279.     _settextposition(3,ccol - (lmess3 / 2));
  280.     _outtext(mess3);
  281.  
  282.     /* Select and branch to    menu choices */
  283.  
  284.     for (;;) {
  285.         choice = menu(crow,ccol,mnuMain);
  286.         setturtle(vmode);
  287.  
  288.         switch (choice) {
  289.             case QUIT :
  290.                 _setvideomode (_DEFAULTMODE); exit(0);
  291.             case CIRCLES :
  292.                 circles(); break;
  293.             case SPHERE :
  294.                 sphere(); break;
  295.             case TUNNEL :
  296.                 nextatrib(0);
  297.                 pendown(FALSE);
  298.                 moveto((short)(-xMAX * .3), (short)(yMAX * .3));
  299.                 turn(35);
  300.                 pendown(TRUE);
  301.                 polygons();
  302.                 while (!kbhit())
  303.                     nextcolor();
  304.                 break;
  305.             case SPIRAL :
  306.                 nextatrib(0);
  307.                 spiral((rand() % 50) + 30, (rand() % 4) + 1);
  308.                 while (!kbhit())
  309.                     nextcolor();
  310.                 break;
  311.             case INSPIRAL :
  312.                 nextatrib(0);
  313.                 inspiral((rand() % 12) + 8, (rand() %20) + 2,
  314.                     (rand() % 30) + 1);
  315.                 while (!kbhit())
  316.                     nextcolor();
  317.                 break;
  318.             case ADJUST :
  319.                 adjust();
  320.                 _setvideomode(_DEFAULTMODE);
  321.                 continue;
  322.             case CHANGE :
  323.                 for (;;) {
  324.                     _setvideomode (_DEFAULTMODE);
  325.                     vmode =    modes[menu(crow,ccol,mnuModes)];
  326.                     if (!setturtle(vmode)) {
  327.                         _settextposition(1,22);
  328.                         _outtext("Mode not available on this machine.\n");
  329.                     } else
  330.                         break;
  331.                 }
  332.                 _setvideomode (_DEFAULTMODE);
  333.                 continue;
  334.         }
  335.         _bios_keybrd(_KEYBRD_READ);
  336.         _setvideomode (_DEFAULTMODE);
  337.     }
  338.     return (0);
  339. }
  340.  
  341. /* Put circles of varying sizes    and colors on screen in    a round    pattern    */
  342.  
  343. void circles()
  344. {
  345.     int i, x, y;
  346.     long tb;
  347.  
  348.     tb = _getbkcolor();
  349.         if ((vc.mode < _HRESBW) || (tc.numAtribs == 2))
  350.         fillstate(FALSE);
  351.     else {
  352.         fillstate(TRUE);
  353.         _setbkcolor(_BRIGHTWHITE);
  354.     }
  355.     pendown(FALSE);
  356.     for (;;) {
  357.         if (tc.numAtribs <= 4)
  358.             nextcolor();
  359.         for (i = 5; i <= 150; ++i) {    /* Draw    circles    */
  360.             x = (int)((xMAX-30) * atan(sin(i / PI)));
  361.             y = (int)((yMAX-30) * atan(cos(i / PI)));
  362.             penatrib(nextatrib(DEFAULT));
  363.             moveto(x,y);
  364.             circle (i % 30);
  365.             if (kbhit()) {
  366.                 _setbkcolor(tb);
  367.                 pendown(TRUE);
  368.                 return;
  369.             }
  370.         }
  371.     }
  372. }
  373.  
  374. /* Draw    and fill sphere; rotate    colors in EGA modes;
  375.    change palette in CGA modes */
  376.  
  377. void sphere()
  378. {
  379.     int ix, x, y, border, inc;
  380.  
  381.     y = x = (int)(tc.yCnt * 0.9);
  382.     fillstate(FALSE);
  383.     nextatrib(0);
  384.     inc = y / 14;
  385.     border = penatrib(DEFAULT);
  386.     borderatrib(border);
  387.     for (ix = inc; ix <= x; ix += (inc * 2))        /* Draw circles */
  388.         ellipse(ix, y);
  389.     fillstate(TRUE);
  390.     pendown(FALSE);
  391.     turn(90);
  392.     x /= 2;
  393.     moveto(-x + inc,0);
  394.     while (tc.xCur <= (x - inc)) {                  /* Fill circles */
  395.         penatrib(nextatrib(DEFAULT));
  396.         fillin();
  397.         move(inc);
  398.     }
  399.     while (!kbhit())                                /* Rotate colors */
  400.         nextcolor();
  401.     pendown(TRUE);
  402. }
  403.  
  404. /* Draw    polygons of increasing size by incrementing the    number of sides.
  405.    Return 1 for user interrupt, 0 for edge of screen encountered. */
  406.  
  407. int polygons()
  408. {
  409.     int sides = 3, size = 2, atrib = 1;
  410.     for (;;) {
  411.         penatrib(nextatrib(atrib++ % NLASTATR));
  412.         if (!poly(sides++,size++))
  413.             return(0);
  414.         if (kbhit())
  415.             return(1);
  416.     }
  417. }
  418.  
  419. /* Draw    a spiral by increasing each side of a rotating figure.
  420.     <angle> determines tightness.
  421.     <inc> determines size.
  422.    Return 1 for user interrupt, 0 for edge of screen encountered. */
  423.  
  424. int spiral(int angle, int inc)
  425. {
  426.     int side = 1, atrib = 1;
  427.  
  428.     for (;;) {
  429.         penatrib(nextatrib(atrib++ % NLASTATR));
  430.         if (!move(side += inc))
  431.             return(0);
  432.         turn(angle);
  433.         if (kbhit())
  434.             return(1);
  435.     }
  436. }
  437.  
  438. /* Draw    an inverted spiral by increasing each angle of a rotating figure.
  439.     <side> determines size.
  440.     <angle> determines shape.
  441.     <inc> determines tightness and shape.
  442.    Return 1 for user interrupt, 0 for edge of screen encountered. */
  443.  
  444. int inspiral(int side, int angle, int inc)
  445. {
  446.     int atrib = 1;
  447.  
  448.     for (;;) {
  449.         penatrib(nextatrib(atrib++ % NLASTATR));
  450.         if (!move(side))
  451.             return(0);
  452.         turn(angle += inc);
  453.         if (kbhit())
  454.             return(1);
  455.     }
  456. }
  457.  
  458. /* Draw    an adjustable circle to    enable the user    to visually adjust the
  459.    screen aspect. */
  460.  
  461. void adjust()
  462. {
  463.     int i, y, pen, radius = (int)(yMAX * .6);
  464.     char buffer[3];
  465.  
  466.     pen = penatrib(DEFAULT);
  467.     _outtext("Modify initial structure\nvalues in program");
  468.     _outtext("\n\nAdjust with cursor keys: ");
  469.     _outtext("\n UP - adjust up");
  470.     _outtext("\n DOWN - adjust down");
  471.     _outtext("\n ENTER - finished\n\n");
  472.     _outtext("xUnits   125\n");
  473.     for (;;) {
  474.         y = (int)tc.yUnits;
  475.         penatrib(pen);
  476.         home();
  477.         pendown(FALSE);        /* Draw white circle with cross. */
  478.         moveto(75,0);
  479.         circle(radius);
  480.         for (i = 1; i <= 4; i++) {
  481.             pendown(TRUE);
  482.             move(radius);
  483.             turn(180);
  484.             pendown(FALSE);
  485.             move(radius);
  486.             turn(90);
  487.         }
  488.  
  489.         _settextposition(11,1); /* Show units and adjust */
  490.         _outtext("yUnits   ");
  491.         ltoa(tc.yUnits,buffer,10);
  492.         _outtext(buffer);
  493.         _outtext(" ");
  494.         switch ((_bios_keybrd(_KEYBRD_READ) & 0xff00) >> 8) {
  495.             case UP    :
  496.                 --y;
  497.                 break;
  498.             case DOWN :
  499.                 ++y;
  500.                 break;
  501.             case ENTER :
  502.                 tc.yUnits = y;
  503.                 return;
  504.         }
  505.         penatrib(0);            /* Erase circle with black */
  506.         moveto(75,0);
  507.         circle(radius);
  508.         for (i = 1; i <= 4; i++) {
  509.             pendown(TRUE);
  510.             move(radius);
  511.             turn(180);
  512.             pendown(FALSE);
  513.             move(radius);
  514.             turn(90);
  515.         }
  516.         tc.yUnits = y;
  517.     }
  518. }
  519.  
  520. /* Put menu on screen.
  521.     Starting <row> and <column>.
  522.     Array of menu <items> strings.
  523.     Global structure variable <menus> determines:
  524.         Colors of border, normal items,    and selected item.
  525.         Centered or left justfied.
  526.         Border characters.
  527.    Returns number of item selected. */
  528.  
  529. int menu(int row, int col, char * *items)
  530. {
  531.     int i, num, max = 2, prev, curr = 0;
  532.     int litem[25];
  533.     long bcolor;
  534.  
  535.     cursor(TCURSOROFF);
  536.     bcolor = _getbkcolor();
  537.  
  538.     /* Count items,    find longest, and put length of    each in    array */
  539.  
  540.     for (num = 0; items[num]; num++) {
  541.         litem[num] = strlen(items[num]);
  542.         max = (litem[num] > max) ? litem[num] :    max;
  543.     }
  544.     max += 2;
  545.  
  546.     if (menus.centered) {
  547.         row -= num / 2;
  548.         col -= max / 2;
  549.     }
  550.  
  551.     /* Draw    menu box */
  552.  
  553.     _settextcolor(menus.fgBorder);
  554.     _setbkcolor(menus.bgBorder);
  555.     box(row++,col++,num,max);
  556.  
  557.     /* Put items in    menu */
  558.  
  559.     for (i = 0; i <    num; ++i) {
  560.         if (i == curr) {
  561.             _settextcolor(menus.fgSelect);
  562.             _setbkcolor(menus.bgSelect);
  563.         } else {
  564.             _settextcolor(menus.fgNormal);
  565.             _setbkcolor(menus.bgNormal);
  566.         }
  567.         itemize(row+i,col,items[i],max - litem[i]);
  568.     }
  569.  
  570.     /* Get selection */
  571.  
  572.     for (;;) {
  573.         switch ((_bios_keybrd(_KEYBRD_READ) & 0xff00) >> 8) {
  574.             case UP    :
  575.                 prev = curr;
  576.                 curr = (curr > 0) ? (--curr % num) : num-1;
  577.                 break;
  578.             case DOWN :
  579.                 prev = curr;
  580.                 curr = (curr < num) ? (++curr %    num) : 0;
  581.                 break;
  582.             case ENTER :
  583.                 _setbkcolor(bcolor);
  584.                 return(curr);
  585.             default    :
  586.                 continue;
  587.         }
  588.         _settextcolor(menus.fgSelect);
  589.         _setbkcolor(menus.bgSelect);
  590.         itemize(row+curr,col,items[curr],max - litem[curr]);
  591.         _settextcolor(menus.fgNormal);
  592.         _setbkcolor(menus.bgNormal);
  593.         itemize(row+prev,col,items[prev],max - litem[prev]);
  594.     }
  595. }
  596.  
  597. /* Draw    menu box.
  598.     <row> and <col> are upper left of box.
  599.     <hi> and <wid> are height and width. */
  600.  
  601. void box(int row, int col, int hi, int wid)
  602. {
  603.     int i;
  604.     char temp[80];
  605.  
  606.     _settextposition(row,col);
  607.     temp[0] = *menus.nw;
  608.     memset(temp+1,*menus.ew,wid);
  609.     temp[wid+1] = *menus.ne;
  610.     temp[wid+2] = 0;
  611.     _outtext(temp);
  612.     for (i = 1; i <= hi; ++i) {
  613.         _settextposition(row+i,col);
  614.         _outtext(menus.ns);
  615.         _settextposition(row+i,col+wid+1);
  616.         _outtext(menus.ns);
  617.     }
  618.     _settextposition(row+hi+1,col);
  619.     temp[0] = *menus.sw;
  620.     memset(temp+1,*menus.ew,wid);
  621.     temp[wid+1] = *menus.se;
  622.     temp[wid+2] = 0;
  623.     _outtext(temp);
  624. }
  625.  
  626. /* Put an item in menu.
  627.     <row> and <col> are left position.
  628.     <str> is the string item.
  629.     <len> is the number of blanks to fill. */
  630.  
  631. void itemize(int row, int col, char *str, int len)
  632. {
  633.     char temp[80];
  634.  
  635.     _settextposition(row,col);
  636.     _outtext(" ");
  637.     _outtext(str);
  638.     memset(temp,' ',len--);
  639.     temp[len] = 0;
  640.     _outtext(temp);
  641. }
  642.  
  643. /* Rotate to next color attribute.
  644.     <init> initializes new starting color.
  645.     (specify DEFAULT to rotate to next color)
  646.    Return rotated color attribute. */
  647.  
  648. int nextatrib(int init)
  649. {
  650.     static int atr;
  651.  
  652.     if (tc.numAtribs == 2)
  653.         return(atr = !atr);
  654.     if (!(init == DEFAULT))
  655.         atr = init;
  656.     return(atr = (atr % (tc.numAtribs-1) + 1));
  657. }
  658.  
  659. /* Rotate to next palette array for EGA and higher.
  660.    Rotate palette for CGA color. */
  661.  
  662. void nextcolor()
  663. {
  664.     static int co = 0;
  665.     int w, i;
  666.  
  667.     if ((vc.adapter <= _CGA) || !tc.numColors)
  668.         return;
  669.     if ((--co < 0) || (co >= tc.numColors - 1))
  670.         co = tc.numColors - 1;
  671.     w = co;
  672.         for (i = LASTATR-1; i > 0; --i) {
  673.             _remappalette(i, wColors[w]);
  674.             if (--w < 0)
  675.                 w = tc.numColors - 1;
  676.         }
  677.         
  678. }
  679.  
  680. /* Set the display mode and establish turtle defaults.
  681.     <mode> is the mode to set.
  682.    Returns 0 if    mode is    invalid, else returns nonzero. */
  683.  
  684. short setturtle(short mode)
  685. {
  686.     int ret, i = 0, btm, top = 63, inc, red = 0, green = 0, blue = 0;
  687.  
  688.     _getvideoconfig(&vc);
  689.     if (mode < _MRES4COLOR)
  690.         return(0);
  691.     if (!(mode == vc.mode))    {
  692.         if(!(ret = _setvideomode(mode)))
  693.             return(0);
  694.         _getvideoconfig(&vc);
  695.     } else
  696.         ret = mode;
  697.  
  698.     home();
  699.     switch (vc.mode) {              /* Set palette defaults */
  700.         case _ERESNOCOLOR :
  701.         case _HERCMONO :
  702.             tc.numColors = 0;
  703.             tc.numAtribs = 2;
  704.             return(ret);
  705.         case _MRES256COLOR :
  706.             tc.numColors = tc.numAtribs = 125;
  707.             inc = btm = 12;
  708.             break;
  709.         case _ERESCOLOR :
  710.         case _VRES16COLOR :
  711.         /* For full 64 color palette, btm = 0; tc.numColors = 64 */
  712.             inc = btm = 16; tc.numColors = 27;
  713.                         break;
  714.         case _MRES4COLOR :
  715.         case _MRESNOCOLOR :
  716.             inc = 32; btm = 0; tc.numColors = 8;
  717.             break;
  718.         default:
  719.             tc.numColors = 16;
  720.             memcpy(wColors,iColors,16 * sizeof(iColors[0]));
  721.             _remapallpalette(iColors);
  722.             nextcolor();
  723.             return(ret);
  724.     }
  725.  
  726.     /* Fill palette arrays */
  727.     for (blue = btm; blue <= top; blue += inc)
  728.         for (green = btm; green <= top; green += inc)
  729.             for (red = btm; red <= top; red += inc)
  730.                 wColors[i++] = RGB(red, green, blue);
  731.     nextcolor();
  732.     return(ret);
  733. }
  734.  
  735. /* Sets    initial    turtle parameters. Use to reset    without    changing mode. */
  736.  
  737. void home()
  738. {
  739.     float ratio;
  740.  
  741.     if (vc.mode == _MRES256COLOR)
  742.         tc.numAtribs = 125;
  743.     else
  744.         tc.numAtribs = vc.numcolors;
  745.     tc.xCnt = vc.numxpixels;
  746.     tc.yCnt = vc.numypixels;
  747.     _setlogorg(tc.xCnt / 2, tc.yCnt / 2);
  748.  
  749.     ratio = (float)(tc.xUnits * tc.yCnt) / (tc.yUnits * tc.xCnt);
  750.     tc.yCnt /= ratio;
  751.  
  752.     tc.xCur = 0;
  753.     tc.yCur = 0;
  754.     tc.isPen = 1;
  755.     _moveto(0, 0);
  756.     tc.angle = 0;
  757.     _remappalette(LASTATR,_BRIGHTWHITE);
  758.     borderatrib(LASTATR);
  759.     penatrib(LASTATR);
  760.     fillstate(_GBORDER);
  761. }
  762.  
  763. /* Makes the turtle pen    used in    move() and moveto() visible or invisible.
  764.     <state> can be TRUE (visible), FALSE (invisible),
  765.     or DEFAULT (return current)
  766.    Returns current state. */
  767.  
  768. int pendown(int state)
  769. {
  770.     switch (state) {
  771.         case TRUE:
  772.             tc.isPen = TRUE;
  773.             break;
  774.         case FALSE:
  775.             tc.isPen = FALSE;
  776.     }
  777.     return(tc.isPen);
  778. }
  779.  
  780. /* Determines whether figures should be filled.
  781.     <state> can be TRUE (fill), FALSE (border only),
  782.     or DEFAULT (return current)
  783.    Returns current state. */
  784.  
  785. short fillstate(short state)
  786. {
  787.     switch (state) {
  788.         case _GBORDER:
  789.         case FALSE:
  790.             tc.isFill = _GBORDER;
  791.             break;
  792.         case _GFILLINTERIOR:
  793.         case TRUE:
  794.             tc.isFill = _GFILLINTERIOR;
  795.     }
  796.     return(tc.isFill);
  797. }
  798.  
  799. /* Sets the color attribute of the pen.
  800.     <atrib> is new atribute (use DEFAULT to get current).
  801.    Returns current color attribute. */
  802.  
  803. short penatrib(short atrib)
  804. {
  805.     if (!(atrib == DEFAULT)) {
  806.         _setcolor(tc.atrib = atrib);
  807.     }
  808.     return(tc.atrib);
  809. }
  810.  
  811. /* Sets the color attribute to be used as a boundary in fills.
  812.     <border> is new border (use DEFAULT to get current).
  813.    Returns border attribute. */
  814.  
  815. short borderatrib(short border)
  816. {
  817.     if (!(border ==    DEFAULT))
  818.             tc.border = border;
  819.     return(tc.border);
  820. }
  821.  
  822. /* Sets a new turtle <angle> relative to the current angle.
  823.    Returns the new angle. */
  824.  
  825. short turn(short angle)
  826. {
  827.     return(tc.angle    = ((tc.angle + angle) %    CIRCUMFERENCE));
  828. }
  829.  
  830. /* Sets a specified turtle <angle>.
  831.    Returns the new angle. */
  832.  
  833. short turnto(short angle)
  834. {
  835.     return(tc.angle    = (angle % CIRCUMFERENCE));
  836. }
  837.  
  838. /* Moves from the current position in the current direction. A line is
  839.    drawn if the    pen is down. The current position is reset.
  840.     <distance> is the adjusted length of line.
  841.    Returns 0 if    the new    position is off    the screen. */
  842.  
  843. short move(short distance)
  844. {
  845.     short dX, dY;
  846.     double workangle;
  847.  
  848.     workangle = (tc.angle -    90) * PI / HALFCIRCUMFERENCE;
  849.     dX = (short)(distance * cos(workangle));
  850.     dY = (short)(distance * sin(workangle));
  851.     if (tc.isPen)
  852.         _lineto(tc.xCur + dX, adj(tc.yCur + dY));
  853.     else
  854.         _moveto(tc.xCur + dX, adj(tc.yCur + dY));
  855.     tc.xCur += dX;
  856.     tc.yCur += dY;
  857.     return(onscreen());
  858. }
  859.  
  860. /* Moves from the current position to a    specified position. A line is
  861.    drawn if the    pen is down. The current position is reset.
  862.     <x> and <y> are destination coordinates.
  863.    Returns 0 if new position is off screen. */
  864.  
  865. short moveto(short x, short y)
  866. {
  867.     if (tc.isPen)
  868.         _lineto(x, adj(y));
  869.     else
  870.         _moveto(x, adj(y));
  871.     tc.xCur = x;
  872.     tc.yCur = y;
  873.     return(onscreen());
  874. }
  875.  
  876. /* Draws a polygon
  877.     <number> specifies how many sides.
  878.     <side> specifies the length of each side.
  879.    Returns 0 if any part of polygon is off screen. */
  880.  
  881. short poly(short number, short side)
  882. {
  883.     int i, ret = 1;
  884.     double angle;
  885.  
  886.     angle = (double)(360 / number);
  887.     for (i = 1; i <= number; ++i) {
  888.         ret = move(side) && ret;
  889.         turn((short)angle);
  890.     }
  891.     return(ret);
  892. }
  893.  
  894. /* Adjusts a specified <y> value for screen aspect.
  895.    Returns the new value. */
  896.  
  897. short adj(short y)
  898. {
  899.     if (y)
  900.         y = (short)(((long)y * (tc.xUnits*vc.numypixels)) /
  901.                        (tc.yUnits*vc.numxpixels));
  902.     return(y);
  903. }
  904.  
  905. /* Change the cursor shape.
  906.     <value> has starting line in upper byte, ending line in lower byte.
  907.    Returns the previous    cursor value. */
  908.  
  909. unsigned cursor(unsigned value)
  910. {
  911.     union REGS inregs, outregs;
  912.     int ret;
  913.  
  914.     inregs.h.ah = 3;    /* Get old cursor */
  915.     inregs.h.bh = 0;
  916.     int86(0x10,&inregs,&outregs);
  917.     ret = outregs.x.cx;
  918.  
  919.     inregs.h.ah = 1;    /* Set new cursor */
  920.     inregs.x.cx = value;
  921.     int86(0x10,&inregs,&outregs);
  922.  
  923.     return(ret);
  924. }
  925.