home *** CD-ROM | disk | FTP | other *** search
/ CICA 1995 May / cica_0595_4.zip / cica_0595_4 / UTIL / MSWSRC35 / GRAPHICS.CPP < prev    next >
C/C++ Source or Header  |  1993-08-25  |  28KB  |  1,314 lines

  1. /*
  2.  *      graphics.c          logo graphics module          mak
  3.  *
  4.  *    Copyright (C) 1989 The Regents of the University of California
  5.  *    This Software may be copied and distributed for educational,
  6.  *    research, and not for profit purposes provided that this
  7.  *    copyright and statement are included in all such copies.
  8.  *
  9.  */
  10.  
  11. #include "logo.h"
  12. /*   #include "globals.h"   has been moved further down */
  13. #include <math.h>
  14.  
  15. #ifdef mac
  16. #include "macterm.h"
  17. #else
  18. #ifdef ibm
  19. #ifdef __ZTC__
  20. #include <fg.h>
  21. #include "ztcterm.h"
  22. #else
  23. //ggm#include "ibmterm.h"
  24. #endif
  25. #else
  26. #ifdef x_window
  27. #include "xgraphics.h"
  28. #else
  29. #include "nographics.h"
  30. #endif
  31. #endif
  32. #endif
  33.  
  34. #include "globals.h"
  35.  
  36. #ifdef __ZTC__
  37. #define total_turtle_bottom_max (-(MaxY/2))
  38. #else
  39. #define total_turtle_bottom_max turtle_bottom_max
  40. #endif
  41.  
  42. extern int status_flag;
  43.  
  44. /* NOTE: See the files (macterm.c and macterm.h) or (ibmterm.c and ibmterm.h)
  45.    for examples of the functions and macros that this file assumes exist. */
  46.  
  47. mode_type current_mode = wrapmode;
  48. FLONUM turtle_x = 0.0, turtle_y = 0.0, turtle_heading = 0.0;
  49. BOOLEAN turtle_shown = TRUE;
  50. FLONUM x_scale = 1.0, y_scale = 1.0;
  51. FLONUM wanna_x = 0.0, wanna_y = 0.0;
  52. BOOLEAN out_of_bounds = FALSE;
  53.  
  54. //char record[GR_SIZE];
  55. int record_index = 0;
  56. pen_info orig_pen;
  57. int forward_count = 0;
  58.  
  59. BOOLEAN record_next_move = FALSE, refresh_p = TRUE;
  60.  
  61. /************************************************************/
  62.  
  63. double pfmod(double x, double y) {
  64.     double temp = fmod(x,y);
  65.  
  66.     if (temp < 0) return temp+y;
  67.     return temp;
  68. }
  69.  
  70. FLONUM cut_error(FLONUM n)
  71. {
  72.     n *= 1000000.0;
  73.     n = (n > 0.0 ? floor(n) : ceil(n));
  74.     n /= 1000000.0;
  75.     if (n == -0.0) n = 0.0;
  76.     return(n);
  77. }
  78.  
  79. FIXNUM g_round(FLONUM n)
  80. {
  81.     n += (n < 0.0 ? -0.5 : 0.5);
  82.     if (n < 0.0)
  83.     return((FIXNUM)ceil(n));
  84.     return((FIXNUM)floor(n));
  85. }
  86.  
  87. /************************************************************/
  88.  
  89. void draw_turtle()
  90. {
  91.     if (turtle_shown) ibmturt(0);
  92.     return;
  93.  
  94.     draw_turtle_helper();
  95.     /* all that follows is for "turtle wrap" effect */
  96.     if ((turtle_y > turtle_top_max - turtle_height) &&
  97.         (current_mode == wrapmode)) {
  98.     turtle_y -= (screen_height + 1);
  99.     draw_turtle_helper();
  100.     check_x_high();
  101.     check_x_low();
  102.     turtle_y += (screen_height + 1);
  103.     }
  104.     if ((turtle_y < turtle_bottom_max + turtle_height) &&
  105.         (current_mode == wrapmode)) {
  106.     turtle_y += (screen_height + 1);
  107.     draw_turtle_helper();
  108.     check_x_high();
  109.     check_x_low();
  110.     turtle_y -= (screen_height + 1);
  111.     }
  112.     check_x_high();
  113.     check_x_low();
  114. }
  115.  
  116. void check_x_high()
  117. {
  118.     if ((turtle_x > turtle_right_max - turtle_height) &&
  119.         (current_mode == wrapmode)) {
  120.     turtle_x -= (screen_width + 1);
  121.     draw_turtle_helper();
  122.     turtle_x += (screen_width + 1);
  123.     }
  124. }
  125.  
  126. void check_x_low()
  127. {
  128.     if ((turtle_x < turtle_left_max + turtle_height) &&
  129.         (current_mode == wrapmode)) {
  130.     turtle_x += (screen_width + 1);
  131.     draw_turtle_helper();
  132.     turtle_x -= (screen_width + 1);
  133.     }
  134. }
  135.  
  136. void draw_turtle_helper()
  137. {
  138.   ibmturt(0);
  139. }
  140.  
  141. /*
  142. draw_turtle_helper()
  143. {
  144.     pen_info saved_pen;
  145.     FLONUM real_heading;
  146.     int left_x, left_y, right_x, right_y, top_x, top_y, center_x, center_y;
  147.     
  148.     prepare_to_draw;
  149.     prepare_to_draw_turtle;
  150.     save_pen(&saved_pen);
  151.     plain_xor_pen();
  152.     pen_vis = 0;
  153.     
  154.     real_heading = -turtle_heading + 90.0;
  155.     center_x = screen_right/2;
  156. #ifdef __ZTC__
  157.     center_y = MaxY/2;
  158. #else
  159.     center_y = screen_bottom/2;
  160. #endif
  161.     
  162.     left_x = g_round(turtle_x + x_scale*(FLONUM)(cos((FLONUM)((real_heading + 90.0)*degrad))*turtle_half_bottom));
  163.     left_y = g_round(turtle_y + y_scale*(FLONUM)(sin((FLONUM)((real_heading + 90.0)*degrad))*turtle_half_bottom));
  164.  
  165.     right_x = g_round(turtle_x + x_scale*(FLONUM)(cos((FLONUM)((real_heading - 90.0)*degrad))*turtle_half_bottom));
  166.     right_y = g_round(turtle_y + y_scale*(FLONUM)(sin((FLONUM)((real_heading - 90.0)*degrad))*turtle_half_bottom));
  167.  
  168.     top_x = g_round(turtle_x + x_scale*(FLONUM)(cos((FLONUM)(real_heading*degrad))*turtle_side));
  169.     top_y = g_round(turtle_y + y_scale*(FLONUM)(sin((FLONUM)(real_heading*degrad))*turtle_side));
  170.  
  171.     move_to(center_x + left_x, center_y - left_y);
  172.     line_to(center_x + top_x, center_y - top_y);
  173.     move_to(center_x + right_x, center_y - right_y);
  174.     line_to(center_x + top_x, center_y - top_y);
  175.     move_to(center_x + left_x, center_y - left_y);
  176.     line_to(center_x + right_x, center_y - right_y);
  177.  
  178.     restore_pen(&saved_pen);
  179.     done_drawing_turtle;
  180.     done_drawing;
  181. }
  182. */
  183.  
  184. /************************************************************/
  185.  
  186. void right(FLONUM a)
  187. {
  188.     draw_turtle();
  189.     turtle_heading += a;
  190.     turtle_heading = pfmod(turtle_heading,360.0);
  191.     if (status_flag) update_status_turtleheading();
  192.     draw_turtle();
  193. }
  194.  
  195. NODE *numeric_arg(NODE *args)
  196. {
  197.     NODE *arg = car(args), *val;
  198.  
  199.     val = cnv_node_to_numnode(arg);
  200.     while (val == UNBOUND && NOT_THROWING) {
  201.     gcref(val);
  202.     setcar(args, err_logo(BAD_DATA, arg));
  203.     arg = car(args);
  204.     val = cnv_node_to_numnode(arg);
  205.     }
  206.     setcar(args,val);
  207.     return(val);
  208. }
  209.  
  210. NODE *lright(NODE *arg)
  211. {
  212.     NODE *val;
  213.     FLONUM a;
  214.     
  215.     val = numeric_arg(arg);
  216.     if (NOT_THROWING) {
  217.     if (nodetype(val) == INT)
  218.         a = (FLONUM)getint(val);
  219.     else
  220.         a = getfloat(val);
  221.     right(a);
  222.     }
  223.     return(UNBOUND);
  224. }
  225.  
  226. NODE *lleft(NODE *arg)
  227. {
  228.     NODE *val;
  229.     FLONUM a;
  230.     
  231.     val = numeric_arg(arg);
  232.     if (NOT_THROWING) {
  233.     if (nodetype(val) == INT)
  234.         a = (FLONUM)getint(val);
  235.     else
  236.         a = getfloat(val);
  237.     right(-a);
  238.     }
  239.     return(UNBOUND);
  240. }
  241.  
  242. NODE *larc(NODE *arg)
  243. {
  244.     NODE *val1;
  245.     NODE *val2;
  246.  
  247.     FLONUM angle;
  248.     FLONUM radius;
  249.     FLONUM ang;
  250.     FLONUM tx;
  251.     FLONUM ty;
  252. //    FLONUM oldx;
  253. //    FLONUM oldy;
  254.     FLONUM x;
  255.     FLONUM y;
  256.     FLONUM count;
  257.     FLONUM delta;
  258.     FLONUM i;
  259.  
  260.     int turtle_state;
  261.     int pen_state;
  262.     
  263.     /* get args */
  264.  
  265.     val1 = numeric_arg(arg);
  266.     val2 = numeric_arg(cdr(arg));
  267.  
  268.     if (NOT_THROWING) {
  269.  
  270.     if (nodetype(val1) == INT)
  271.         angle = (FLONUM)getint(val1);
  272.     else
  273.         angle = getfloat(val1);
  274.  
  275.     if (nodetype(val2) == INT)
  276.         radius = (FLONUM)getint(val2);
  277.     else
  278.         radius = getfloat(val2);
  279.  
  280.     prepare_to_draw;
  281.     draw_turtle();
  282.  
  283.     /* save and force turle state */
  284.  
  285.     turtle_state = turtle_shown;
  286.     turtle_shown = 0;
  287.  
  288.     /* grab things before they change and use for restore */
  289.  
  290.     ang = turtle_heading;
  291.     tx = turtle_x;
  292.     ty = turtle_y;
  293.  
  294.     /* calculate resolution parameters */
  295.  
  296.     count = abs(angle*radius/200.0);
  297.     delta = angle/count;
  298.  
  299.     /* draw each line segment of arc (will do wrap) */
  300.  
  301.     for (i=0.0;i<=count;i=i+1.0)
  302.        {
  303.  
  304.        /* calc x y */
  305.  
  306.        x = -sin(ang*3.141592654/180.0)*radius;
  307.        y = -cos(ang*3.141592654/180.0)*radius;
  308.  
  309.        /* jump to begin of first line segment without drawing */
  310.  
  311.        if (i==0.0)
  312.           {
  313.           pen_state = pen_vis;
  314.           pen_vis = 1;
  315.           setpos_helper(make_floatnode(tx+x), make_floatnode(ty+y));
  316.           pen_vis = pen_state;
  317.           }
  318.  
  319.        /* else do segment */
  320.  
  321.        else
  322.           {
  323.           setpos_helper(make_floatnode(tx+x), make_floatnode(ty+y));
  324.           }
  325.  
  326.        ang = ang + delta;
  327.        }
  328.  
  329.     /* assure we draw something and end in the exact right place */
  330.  
  331.     x = -sin((turtle_heading+angle)*3.141592654/180.0)*radius;
  332.     y = -cos((turtle_heading+angle)*3.141592654/180.0)*radius;
  333.  
  334.     setpos_helper(make_floatnode(tx+x), make_floatnode(ty+y));
  335.  
  336.     /* restore state */
  337.  
  338.     turtle_shown = turtle_state;
  339.  
  340.     turtle_x = tx;
  341.     turtle_y = ty;
  342.  
  343.     draw_turtle();
  344.     done_drawing;
  345.     wanna_x = turtle_x;
  346.     wanna_y = turtle_y;
  347.     out_of_bounds = FALSE;
  348.  
  349.     }
  350.     return(UNBOUND);
  351. }
  352.  
  353. void forward(FLONUM d)
  354. {
  355.     prepare_to_draw;
  356.     draw_turtle();
  357.     forward_helper(d);
  358.     draw_turtle();
  359.     done_drawing;
  360.     wanna_x = turtle_x;
  361.     wanna_y = turtle_y;
  362.     out_of_bounds = FALSE;
  363. }
  364.  
  365. void forward_helper(FLONUM d)
  366. {
  367.     FLONUM real_heading, dx, dy, x1, y1, x2, y2;
  368. //    FLONUM intercept;
  369.     
  370.     if (forward_count++ > 32) return;
  371.  
  372.     real_heading = -turtle_heading + 90.0;
  373.     x1 = screen_x_coord;
  374.     y1 = screen_y_coord;
  375.     dx = (FLONUM)(cos((FLONUM)(real_heading*degrad))*d*x_scale);
  376.     dy = (FLONUM)(sin((FLONUM)(real_heading*degrad))*d*y_scale);
  377.     x2 = x1 + dx;
  378.     y2 = y1 - dy;
  379.     
  380.     move_to(g_round(x1), g_round(y1));
  381.     if (record_next_move) {
  382.     save_move();
  383.     record_next_move = FALSE;
  384.     }
  385.     
  386.     if (check_throwing) return;
  387.     
  388.     if (current_mode == windowmode ||
  389.     (x2 >= screen_left && x2 <= screen_right &&
  390.      y2 >= screen_top && y2 <= screen_bottom)) {
  391.     turtle_x = turtle_x + dx;
  392.     turtle_y = turtle_y + dy;
  393.     line_to(g_round(x2), g_round(y2));
  394.     save_line();
  395.     }
  396.     else
  397.     if (!wrap_right(d, x1, y1, x2, y2))
  398.         if (!wrap_left(d, x1, y1, x2, y2))
  399.         if (!wrap_up(d, x1, y1, x2, y2))
  400.             wrap_down(d, x1, y1, x2, y2);
  401.  
  402.     forward_count--;
  403.  
  404. }
  405.  
  406. int wrap_right(FLONUM d, FLONUM x1, FLONUM y1, FLONUM x2, FLONUM y2)
  407. {
  408.     FLONUM yi;
  409.     
  410.     if (x2 > screen_right) {
  411.     yi = ((y2 - y1)/(x2 - x1)) * (screen_right - x1) + y1;
  412.     if (yi >= screen_top && yi <= screen_bottom) {
  413.         line_to(screen_right, g_round(yi));
  414.         save_line();
  415.         record_next_move = TRUE;
  416.         turtle_x = turtle_left_max;
  417.         turtle_y = -yi;
  418.         if (current_mode == wrapmode) {
  419.         forward_helper(d * ((x2 - screen_right)/(x2 - x1)));
  420.         return(1);
  421.         }
  422.         turtle_x = turtle_right_max;
  423.         err_logo(TURTLE_OUT_OF_BOUNDS, NIL);
  424.     }
  425.     }
  426.     return(0);
  427. }
  428.  
  429. int wrap_left(FLONUM d, FLONUM x1, FLONUM y1, FLONUM x2, FLONUM y2)
  430. {
  431.     FLONUM yi;
  432.     
  433.     if (x2 < screen_left) {
  434.     yi = ((y2 - y1)/(x1 - x2)) * (x1 - screen_left) + y1;
  435.     if (yi >= screen_top && yi <= screen_bottom) {
  436.         line_to(screen_left, g_round(yi));
  437.         save_line();
  438.         record_next_move = TRUE;
  439.         turtle_x = turtle_right_max;
  440.         turtle_y = -yi;
  441.         if (current_mode == wrapmode) {
  442.         forward_helper(d * ((screen_left - x2)/(x1 - x2)));
  443.         return(1);
  444.         }
  445.         turtle_x = turtle_left_max;
  446.         err_logo(TURTLE_OUT_OF_BOUNDS, NIL);        
  447.     }
  448.     }
  449.     return(0);
  450. }
  451.  
  452. int wrap_up(FLONUM d, FLONUM x1, FLONUM y1, FLONUM x2, FLONUM y2)
  453. {
  454.     FLONUM xi;
  455.     
  456.     if (y2 < screen_top) {
  457.     xi = ((x2 - x1)/(y1 - y2)) * (y1 - screen_top) + x1;
  458.     if (xi >= screen_left && xi <= screen_right) {
  459.         line_to(g_round(xi), screen_top);
  460.         save_line();
  461.         record_next_move = TRUE;
  462.         turtle_x = xi;
  463.         turtle_y = -turtle_bottom_max;
  464.         if (current_mode == wrapmode) {
  465.         forward_helper(d * ((screen_top - y2)/(y1 - y2)));
  466.         return(1);
  467.         }
  468.         turtle_y = -turtle_top_max;
  469.         err_logo(TURTLE_OUT_OF_BOUNDS, NIL);
  470.     }
  471.     }
  472.     return(0);
  473. }
  474.  
  475. int wrap_down(FLONUM d, FLONUM x1, FLONUM y1, FLONUM x2, FLONUM y2)
  476. {
  477.     FLONUM xi;
  478.     
  479.     if (y2 > screen_bottom) {
  480.     xi = ((x2 - x1)/(y2 - y1)) * (screen_bottom - y1) + x1;
  481.     if (xi >= screen_left && xi <= screen_right) {
  482.         line_to(g_round(xi), screen_bottom);
  483.         save_line();
  484.         record_next_move = TRUE;
  485.         turtle_x = xi;
  486.         turtle_y = -turtle_top_max;
  487.         if (current_mode == wrapmode) {
  488.         forward_helper(d * ((y2 - screen_bottom)/(y2 - y1)));
  489.         return(1);
  490.         }
  491.         turtle_y = -turtle_bottom_max;
  492.         err_logo(TURTLE_OUT_OF_BOUNDS, NIL);
  493.     }
  494.     }
  495.     return(0);
  496. }
  497.  
  498. NODE *lforward(NODE *arg)
  499. {
  500.     NODE *val;
  501.     FLONUM d;
  502.     
  503.     val = numeric_arg(arg);
  504.     if (NOT_THROWING) {
  505.     if (nodetype(val) == INT)
  506.         d = (FLONUM)getint(val);
  507.     else
  508.         d = getfloat(val);
  509.     forward(d);
  510.     }
  511.     return(UNBOUND);
  512. }
  513.  
  514. NODE *lback(NODE *arg)
  515. {
  516.     NODE *val;
  517.     FLONUM d;
  518.     
  519.     val = numeric_arg(arg);
  520.     if (NOT_THROWING) {
  521.     if (nodetype(val) == INT)
  522.         d = (FLONUM)getint(val);
  523.     else
  524.         d = getfloat(val);
  525.     forward(-d);
  526.     }
  527.     return(UNBOUND);
  528. }
  529.  
  530. NODE *lshowturtle()
  531. {
  532.     prepare_to_draw;
  533.     if (!turtle_shown) {
  534.     turtle_shown = TRUE;
  535.         if (status_flag) update_status_turtlevisability();
  536.     draw_turtle();
  537.     }
  538.     done_drawing;
  539.     return(UNBOUND);
  540. }
  541.  
  542. NODE *lhideturtle()
  543. {
  544.     prepare_to_draw;
  545.     if (turtle_shown) {
  546.     draw_turtle();
  547.     turtle_shown = FALSE;
  548.         if (status_flag) update_status_turtlevisability();
  549.     }
  550.     done_drawing;
  551.     return(UNBOUND);
  552. }
  553.  
  554. NODE *lshownp()
  555. {
  556.     return(turtle_shown ? Truex : Falsex);
  557. }
  558.  
  559. NODE *lsetheading(NODE *arg)
  560. {
  561.     NODE *val;
  562.     
  563.     val = numeric_arg(arg);
  564.     if (NOT_THROWING) {
  565.     draw_turtle();
  566.     if (nodetype(val) == INT)
  567.         turtle_heading = (FLONUM)getint(val);
  568.     else
  569.         turtle_heading = getfloat(val);
  570.     turtle_heading = pfmod(turtle_heading,360.0);
  571.         if (status_flag) update_status_turtleheading();
  572.     draw_turtle();
  573.     }
  574.     return(UNBOUND);
  575. }
  576.  
  577. NODE *lheading()
  578. {
  579.     return(make_floatnode(turtle_heading));
  580. }
  581.  
  582. NODE *vec_arg_helper(NODE *args, BOOLEAN floatok)
  583. {
  584.     NODE *arg = car(args), *val1, *val2;
  585.  
  586.     while (NOT_THROWING) {
  587.     if (arg != NIL &&
  588.     is_list(arg) &&
  589.     cdr(arg) != NIL &&
  590.     cddr(arg) == NIL) {
  591.         val1 = cnv_node_to_numnode(car(arg));
  592.         val2 = cnv_node_to_numnode(cadr(arg));
  593.         if (val1 != UNBOUND && val2 != UNBOUND &&
  594.         (floatok || (nodetype(val1) == INT && getint(val1) >= 0 &&
  595.                  nodetype(val2) == INT && getint(val2) >= 0))) {
  596.         setcar(arg, val1);
  597.         setcar(cdr(arg), val2);
  598.         return(arg);
  599.         }
  600.         gcref(val1);
  601.         gcref(val2);
  602.     }
  603.     setcar(args, err_logo(BAD_DATA, arg));
  604.     arg = car(args);
  605.     }
  606.     return(UNBOUND);
  607. }
  608.  
  609. NODE *vec_3_arg_helper(NODE *args, BOOLEAN floatok)
  610. {
  611.     NODE *arg = car(args), *val1, *val2, *val3;
  612.  
  613.     while (NOT_THROWING) {
  614.     if (arg != NIL &&
  615.     is_list(arg) &&
  616.     cdr(arg) != NIL &&
  617.     cddr(arg) != NIL &&
  618.     cddr(cdr(arg)) == NIL) {
  619.         val1 = cnv_node_to_numnode(car(arg));
  620.         val2 = cnv_node_to_numnode(cadr(arg));
  621.         val3 = cnv_node_to_numnode(cadr(cdr(arg)));
  622.         if (val1 != UNBOUND && val2 != UNBOUND && val3 != UNBOUND &&
  623.         (floatok || (nodetype(val1) == INT && getint(val1) >= 0 &&
  624.                  nodetype(val2) == INT && getint(val2) >= 0 &&
  625.                  nodetype(val3) == INT && getint(val3) >= 0))) {
  626.         setcar(arg, val1);
  627.         setcar(cdr(arg), val2);
  628.         setcar(cddr(arg), val3);
  629.         return(arg);
  630.         }
  631.         gcref(val1);
  632.         gcref(val2);
  633.         gcref(val3);
  634.     }
  635.     setcar(args, err_logo(BAD_DATA, arg));
  636.     arg = car(args);
  637.     }
  638.     return(UNBOUND);
  639. }
  640.  
  641. NODE *vector_arg(NODE *args) {
  642.     return vec_arg_helper(args,TRUE);
  643. }
  644.  
  645. NODE *pos_int_vector_arg(NODE *args) {
  646.     return vec_arg_helper(args,FALSE);
  647. }
  648.  
  649. NODE *pos_int_vector_3_arg(NODE *args) {
  650.     return vec_3_arg_helper(args,FALSE);
  651. }
  652.  
  653. FLONUM towards_helper(FLONUM x, FLONUM y, FLONUM from_x, FLONUM from_y)
  654. {
  655.     FLONUM m, a, tx, ty;
  656.  
  657.     tx = from_x/x_scale;
  658.     ty = from_y/y_scale;
  659.  
  660.     if (x != tx || y != ty) {
  661.     if (x == tx)
  662.         a = (y < ty) ? -90 : 90;
  663.     else {
  664.         m = (y - ty)/(x - tx);
  665.         a = atan(m)/degrad;
  666.         if (x < tx) a = fmod(a + 180.0,360.0);
  667.     }
  668.     return -(a - 90.0);
  669.     }
  670.     return(0.0);
  671. }
  672.  
  673. NODE *ltowards(NODE *args)
  674. {
  675.     NODE *xnode, *ynode = UNBOUND, *arg;
  676.     FLONUM x, y;
  677.     
  678.     arg = vector_arg(args);
  679.     if (NOT_THROWING) {
  680.     xnode = car(arg);
  681.     ynode = cadr(arg);
  682.     
  683.     x = ((nodetype(xnode) == FLOAT) ? getfloat(xnode) :
  684.               (FLONUM)getint(xnode));
  685.     y = ((nodetype(ynode) == FLOAT) ? getfloat(ynode) :
  686.               (FLONUM)getint(ynode));
  687.     return make_floatnode(towards_helper(x, y, turtle_x, turtle_y));
  688.     }
  689.     return(UNBOUND);
  690. }
  691.  
  692. NODE *lpos()
  693. {
  694.     return(cons(make_floatnode(cut_error(turtle_x/x_scale)),
  695.     cons(make_floatnode(cut_error(turtle_y/y_scale)), NIL)));
  696. }
  697.  
  698. NODE *lscrunch()
  699. {
  700.     return(cons(make_floatnode(x_scale), cons(make_floatnode(y_scale), NIL)));
  701. }
  702.  
  703. NODE *lhome()
  704. {
  705.     out_of_bounds = FALSE;
  706.     setpos_helper(make_intnode((FIXNUM)0), make_intnode((FIXNUM)0));
  707.     draw_turtle();
  708.     turtle_heading = 0.0;
  709.     draw_turtle();
  710.     return(UNBOUND);
  711. }
  712.  
  713. void cs_helper(int centerp)
  714. {    
  715.     prepare_to_draw;
  716.     clear_screen;
  717.     if (centerp) {
  718.     wanna_x = wanna_y = turtle_x = turtle_y = turtle_heading = 0.0;
  719.         if (status_flag)
  720.         {
  721.         update_status_turtleheading();
  722.         update_status_turtleposition();
  723.         }
  724.     out_of_bounds = FALSE;
  725.     }
  726.     draw_turtle();
  727.     save_pen(&orig_pen);
  728.     p_info_x(orig_pen) = g_round(screen_x_coord);
  729.     p_info_y(orig_pen) = g_round(screen_y_coord);
  730.     record_index = 0;
  731.     done_drawing;
  732. }
  733.  
  734. NODE *lclearscreen()
  735. {
  736.     cs_helper(TRUE);
  737.     return(UNBOUND);
  738. }
  739.  
  740. NODE *lclean()
  741. {
  742.     cs_helper(FALSE);
  743.     return(UNBOUND);
  744. }
  745.  
  746. void setpos_helper(NODE *xnode, NODE *ynode)
  747. {
  748.     FLONUM target_x, target_y, scaled_x, scaled_y, tx, ty, save_heading;
  749.     BOOLEAN wrapping = FALSE;
  750.     
  751.     if (NOT_THROWING) {
  752.     prepare_to_draw;
  753.     draw_turtle();
  754.     move_to(g_round(screen_x_coord), g_round(screen_y_coord));
  755.     target_x = ((xnode == NIL) ?
  756.         turtle_x :
  757.         ((nodetype(xnode) == FLOAT) ? getfloat(xnode) :
  758.          (FLONUM)getint(xnode)));
  759.     target_y = ((ynode == NIL) ?
  760.         turtle_y :
  761.         ((nodetype(ynode) == FLOAT) ? getfloat(ynode) :
  762.          (FLONUM)getint(ynode)));
  763.     scaled_x = target_x * x_scale;
  764.     scaled_y = target_y * y_scale;
  765.     wrapping = scaled_x > turtle_right_max || scaled_x < turtle_left_max ||
  766.            scaled_y < turtle_top_max || scaled_y > turtle_bottom_max;
  767.     if (current_mode == fencemode && wrapping)
  768.         err_logo(TURTLE_OUT_OF_BOUNDS, NIL);
  769.     else if (current_mode == wrapmode && (wrapping || out_of_bounds)) {
  770.         save_heading = turtle_heading;
  771.         turtle_heading = towards_helper(target_x, target_y,
  772.                         wanna_x, wanna_y);
  773.         tx = wanna_x/x_scale;
  774.         ty = wanna_y/y_scale;
  775. #define sq(z) ((z)*(z))
  776.         forward_helper(sqrt(sq(target_x - tx) + sq(target_y - ty)));
  777.         turtle_heading = save_heading;
  778.         wanna_x = scaled_x;
  779.         wanna_y = scaled_y;
  780.         out_of_bounds = wrapping;
  781.     }
  782.     else {
  783.         wanna_x = turtle_x = scaled_x;
  784.         wanna_y = turtle_y = scaled_y;
  785.         out_of_bounds = FALSE;
  786.         line_to(g_round(screen_x_coord), g_round(screen_y_coord));
  787.         save_line();
  788.     }
  789.     done_drawing;
  790.     draw_turtle();
  791.     }
  792. }
  793.  
  794. NODE *lsetpos(NODE *args)
  795. {
  796.     NODE *arg = vector_arg(args);
  797.  
  798.     if (NOT_THROWING) {
  799.     setpos_helper(car(arg), cadr(arg));
  800.     }
  801.     return(UNBOUND);
  802. }
  803.  
  804. NODE *lsetxy(NODE *args)
  805. {
  806.     NODE *xnode, *ynode;
  807.     
  808.     xnode = numeric_arg(args);
  809.     ynode = numeric_arg(cdr(args));
  810.     if (NOT_THROWING) {
  811.     setpos_helper(xnode, ynode);
  812.     }
  813.     return(UNBOUND);
  814. }
  815.  
  816. NODE *lsetx(NODE *args)
  817. {
  818.     NODE *xnode;
  819.     
  820.     xnode = numeric_arg(args);
  821.     if (NOT_THROWING) {
  822.     setpos_helper(xnode, NIL);
  823.     }
  824.     return(UNBOUND);
  825. }
  826.  
  827. NODE *lsety(NODE *args)
  828. {
  829.     NODE *ynode;
  830.     
  831.     ynode = numeric_arg(args);
  832.     if (NOT_THROWING) {
  833.     setpos_helper(NIL, ynode);
  834.     }
  835.     return(UNBOUND);
  836. }
  837.  
  838. NODE *lwrap()
  839. {
  840.     if (turtle_shown) draw_turtle();
  841.     current_mode = wrapmode;
  842.     if (turtle_shown) draw_turtle();
  843.     return(UNBOUND);
  844. }
  845.  
  846. NODE *lfence()
  847. {
  848.     if (turtle_shown) draw_turtle();
  849.     current_mode = fencemode;
  850.     if (turtle_shown) draw_turtle();
  851.     return(UNBOUND);
  852. }
  853.  
  854. NODE *lwindow()
  855. {
  856.     if (turtle_shown) draw_turtle();
  857.     current_mode = windowmode;
  858.     if (turtle_shown) draw_turtle();
  859.     return(UNBOUND);
  860. }
  861.  
  862. NODE *lfill()
  863. {
  864.     if (turtle_shown) draw_turtle();
  865.     logofill();
  866.     if (turtle_shown) draw_turtle();
  867.     return(UNBOUND);
  868. }
  869.  
  870. NODE *llabel(NODE *arg)
  871. {
  872.     char textbuf[MAX_BUFFER_SIZE];
  873. //    short theLength;
  874.  
  875.     print_stringptr = textbuf;
  876.     print_stringlen = MAX_BUFFER_SIZE;
  877.     ndprintf((FILE *)NULL,"%p",car(arg));
  878.     *print_stringptr = '\0';
  879.     
  880.     if (NOT_THROWING) {
  881.     draw_turtle();
  882. #ifdef x_window
  883.     label(textbuf, strlen(textbuf));
  884. #else
  885. #ifdef mac
  886.     theLength = strlen(textbuf);
  887.     c_to_pascal_string(textbuf, theLength);
  888. #endif
  889.     label(textbuf);
  890.     save_string(textbuf);
  891.     record_next_move = TRUE;
  892. #endif
  893.     draw_turtle();
  894.     }
  895.     return(UNBOUND);
  896. }
  897.  
  898. NODE *ltextscreen()
  899. {
  900.     text_screen;
  901.     return(UNBOUND);
  902. }
  903.  
  904. NODE *lsplitscreen()
  905. {
  906.     split_screen;
  907.     return(UNBOUND);
  908. }
  909.  
  910. NODE *lfullscreen()
  911. {
  912.     full_screen;
  913.     return(UNBOUND);
  914. }
  915.  
  916. NODE *lpendownp()
  917. {
  918.     return(pen_vis == 0 ? Truex : Falsex);
  919. }
  920.  
  921. NODE *lpenmode()
  922. {
  923.     return(get_node_pen_mode);
  924. }
  925.  
  926. NODE *lpensize()
  927. {
  928.     return(cons(make_intnode((FIXNUM)pen_width),
  929.     cons(make_intnode((FIXNUM)pen_height), NIL)));
  930. }
  931.  
  932. NODE *lpenpattern()
  933. {
  934.     return(get_node_pen_pattern);
  935. }
  936.  
  937. NODE *lpendown()
  938. {
  939.     pen_vis = 0;
  940.     save_vis();
  941.     return(UNBOUND);
  942. }
  943.  
  944. NODE *lpenup()
  945. {
  946.     if (pen_vis == 0)
  947.     pen_vis--;
  948.     save_vis();
  949.     return(UNBOUND);
  950. }
  951.  
  952. NODE *lpenpaint()
  953. {
  954.     pen_down;
  955.     save_mode();
  956.     return(lpendown());
  957. }
  958.  
  959. NODE *lpenerase()
  960. {
  961.     pen_erase;
  962.     save_mode();
  963.     return(lpendown());
  964. }
  965.  
  966. NODE *lpenreverse()
  967. {
  968.     pen_reverse;
  969.     save_mode();
  970.     return(lpendown());
  971. }
  972.  
  973. NODE *lsetpencolor(NODE *args)
  974. {
  975.     NODE *arg = pos_int_vector_3_arg(args);
  976.  
  977.     if (NOT_THROWING) {
  978.         prepare_to_draw;
  979.     set_pen_color(getint(car(arg)),getint(cadr(arg)),getint(cadr(cdr(arg))));
  980.     save_color_pen();
  981.     }
  982.     return(UNBOUND);
  983. }
  984.  
  985. NODE *lsetfloodcolor(NODE *args)
  986. {
  987.     NODE *arg = pos_int_vector_3_arg(args);
  988.  
  989.     if (NOT_THROWING) {
  990.     set_flood_color(getint(car(arg)),getint(cadr(arg)),getint(cadr(cdr(arg))));
  991.     save_color_flood();
  992.     }
  993.     return(UNBOUND);
  994. }
  995.  
  996. NODE *lsetscreencolor(NODE *args)
  997. {
  998.     NODE *arg = pos_int_vector_3_arg(args);
  999.  
  1000.     if (NOT_THROWING) {
  1001.     set_screen_color(getint(car(arg)),getint(cadr(arg)),getint(cadr(cdr(arg))));
  1002.     save_color_screen();
  1003.     }
  1004.     return(UNBOUND);
  1005. }
  1006.  
  1007. NODE *lsetpensize(NODE *args)
  1008. {
  1009.     NODE *arg = pos_int_vector_arg(args);
  1010.  
  1011.     if (NOT_THROWING) {
  1012.         prepare_to_draw;
  1013.     set_pen_width((int)getint(car(arg)));
  1014.     set_pen_height((int)getint(cadr(arg)));
  1015.     save_size();
  1016.     }
  1017.     return(UNBOUND);
  1018. }
  1019.  
  1020. NODE *lsetpenpattern(NODE *args)
  1021. {    
  1022.     NODE *arg;
  1023.  
  1024.     arg = car(args);
  1025.     ref(arg);
  1026.     while ((arg == NIL || !is_list(arg)) && NOT_THROWING)
  1027.     arg = reref(arg, err_logo(BAD_DATA, arg));
  1028.     
  1029.     if (NOT_THROWING) {
  1030.         prepare_to_draw;
  1031.     set_list_pen_pattern(arg);
  1032.     save_pattern();
  1033.     }
  1034.  
  1035.     deref(arg);
  1036.     return(UNBOUND);
  1037. }
  1038.  
  1039. NODE *lsetscrunch(NODE *args)
  1040. {
  1041.     NODE *xnode, *ynode;
  1042.  
  1043.     xnode = numeric_arg(args);
  1044.     ynode = numeric_arg(cdr(args));
  1045.  
  1046.     if (NOT_THROWING) {
  1047.     prepare_to_draw;
  1048.     if (turtle_shown) {
  1049.         draw_turtle();
  1050.         }
  1051.     x_scale = (nodetype(xnode) == FLOAT) ? getfloat(xnode) :
  1052.                    (FLONUM)getint(xnode);
  1053.     y_scale = (nodetype(ynode) == FLOAT) ? getfloat(ynode) :
  1054.                    (FLONUM)getint(ynode);
  1055.     if (turtle_shown) {
  1056.         draw_turtle();
  1057.         }
  1058.     done_drawing;
  1059. #ifdef __ZTC__
  1060.         {
  1061.             FILE *fp = fopen("scrunch.dat","w");
  1062.             if (fp != NULL) {
  1063.                 fwrite(&x_scale, sizeof(FLONUM), 1, fp);
  1064.                 fwrite(&y_scale, sizeof(FLONUM), 1, fp);
  1065.                 fclose(fp);
  1066.             }
  1067.         }
  1068. #endif
  1069.     }
  1070.     return(UNBOUND);
  1071. }
  1072.  
  1073. //NODE *lmousepos()
  1074. //{
  1075. //    return(cons(make_intnode(mouse_x), cons(make_intnode(mouse_y), NIL)));
  1076. //}
  1077.  
  1078. NODE *lbuttonp()
  1079. {
  1080.     if (button)
  1081.     return(Truex);
  1082.     return(Falsex);
  1083. }
  1084.  
  1085. NODE *ltone(NODE *args)
  1086. {
  1087.     NODE *p, *d;
  1088.     FIXNUM pitch, duration;
  1089.     
  1090.     p = numeric_arg(args);
  1091.     d = numeric_arg(cdr(args));
  1092.     
  1093.     if (NOT_THROWING) {
  1094.     pitch = (nodetype(p) == FLOAT) ? (FIXNUM)getfloat(p) : getint(p);
  1095.     duration = (nodetype(d) == FLOAT) ? (FIXNUM)getfloat(d) : getint(d);
  1096.     tone(pitch, duration);
  1097.     }
  1098.     
  1099.     return(UNBOUND);
  1100. }
  1101.  
  1102. /************************************************************/
  1103. /* The rest of this file implements the recording of moves in
  1104.    the graphics window and the playing back of those moves.  It's
  1105.    needed on machines like the Macintosh where the contents of the
  1106.    graphics window can get erased and need to be redrawn.  On
  1107.    machines where no graphics redrawing is necessary, set the size
  1108.    of the recording buffer to 1 in logo.h. */
  1109.  
  1110. BOOLEAN safe_to_save()
  1111. {
  1112. /*
  1113.     return(refresh_p && record_index < (GR_SIZE - 300));
  1114. */
  1115. return(1);
  1116. }
  1117.  
  1118. void save_lm_helper ()
  1119. {
  1120. /*
  1121.     *(int *)(record + record_index + 2) = pen_x;
  1122.     *(int *)(record + record_index + 4) = pen_y;
  1123.     record_index += 6;
  1124. */
  1125. }
  1126.  
  1127. void save_line()
  1128. {
  1129.     if (status_flag) update_status_turtleposition();
  1130. /*
  1131.     if (safe_to_save()) {
  1132.     record[record_index] = LINEXY;
  1133.     save_lm_helper();
  1134.     }
  1135. */
  1136. }
  1137.  
  1138. void save_move()
  1139. {
  1140.     if (status_flag) update_status_turtleposition();
  1141. /*
  1142.     if (safe_to_save()) {
  1143.     record[record_index] = MOVEXY;
  1144.     save_lm_helper();
  1145.     }
  1146. */
  1147. }
  1148.  
  1149. void save_vis()
  1150. {
  1151.     if (status_flag) update_status_pencontact();
  1152. /*
  1153.     if (safe_to_save()) {
  1154.     record[record_index] = SETPENVIS;
  1155.     record[record_index + 1] = (char)pen_vis;
  1156.     record_index += 2;
  1157.     }
  1158. */
  1159. }
  1160.  
  1161. void save_mode()
  1162. {
  1163.     if (status_flag) update_status_penstyle();
  1164. /*
  1165.     if (safe_to_save()) {
  1166.     record[record_index] = SETPENMODE;
  1167. #ifdef x_window
  1168.     *(GC *)(record + record_index + 2) = pen_mode;
  1169. #else
  1170.     *(int *)(record + record_index + 2) = pen_mode;
  1171. #endif
  1172.     record_index += 4;
  1173.     }
  1174. */
  1175. }
  1176.  
  1177. void save_color_pen()
  1178. {
  1179.     if (status_flag) update_status_pencolor();
  1180. /*
  1181.     if (safe_to_save()) {
  1182.     record[record_index] = SETPENCOLOR;
  1183.     *(long *)(record + record_index + 2) = pen_color;
  1184.     record_index += 6;
  1185.     }
  1186. */
  1187. }
  1188.  
  1189. void save_color_screen()
  1190. {
  1191.     if (status_flag) update_status_screencolor();
  1192. /*
  1193.     if (safe_to_save()) {
  1194.     record[record_index] = SETPENCOLOR;
  1195.     *(long *)(record + record_index + 2) = pen_color;
  1196.     record_index += 6;
  1197.     }
  1198. */
  1199. }
  1200.  
  1201. void save_color_flood()
  1202. {
  1203.     if (status_flag) update_status_floodcolor();
  1204. /*
  1205.     if (safe_to_save()) {
  1206.     record[record_index] = SETPENCOLOR;
  1207.     *(long *)(record + record_index + 2) = pen_color;
  1208.     record_index += 6;
  1209.     }
  1210. */
  1211. }
  1212.  
  1213. void save_size()
  1214. {
  1215.     if (status_flag) update_status_penwidth();
  1216. /*
  1217.     if (safe_to_save()) {
  1218.     record[record_index] = SETPENSIZE;
  1219.     *(int *)(record + record_index + 2) = pen_width;
  1220.     *(int *)(record + record_index + 4) = pen_height;
  1221.     record_index += 6;
  1222.     }
  1223. */
  1224. }
  1225.  
  1226. void save_pattern()
  1227. {
  1228. //    if (status_flag) update_status(SETPENPATTERN);
  1229. /*
  1230.     int count;
  1231.     
  1232.     if (safe_to_save()) {
  1233.     record[record_index] = SETPENPATTERN;
  1234.     get_pen_pattern(&record[record_index + 2]);
  1235.     record_index += 10;
  1236.     }
  1237. */
  1238. }
  1239.  
  1240. void save_string(char s[])
  1241. {
  1242. /*
  1243.     int count;
  1244.  
  1245.     if (safe_to_save()) {
  1246.     record[record_index] = LABEL;
  1247.     record[record_index + 2] = s[0];
  1248.     for (count = 0; count < s[0]; count++)
  1249.         record[record_index + 3 + count] = s[1 + count];
  1250.     record_index += 3 + s[0] + even_p(s[0]);
  1251.     }
  1252. */
  1253. }
  1254.  
  1255. NODE *lrefresh()
  1256. {
  1257.     refresh_p = TRUE;
  1258.     return(UNBOUND);
  1259. }
  1260.  
  1261. NODE *lnorefresh()
  1262. {
  1263.     refresh_p = FALSE;
  1264.     return(UNBOUND);
  1265. }
  1266.  
  1267. void redraw_graphics()
  1268. {
  1269. }
  1270.  
  1271. /* This is called when the graphics coordinate system has been shifted.
  1272.    It adds a constant amount to each x and y coordinate in the record. */
  1273. void resize_record(int dh, int dv)
  1274. {
  1275. /*
  1276.     int r_index = 0;
  1277.     
  1278.     p_info_x(orig_pen) += dh;
  1279.     p_info_y(orig_pen) += dv;
  1280.     
  1281.     while (r_index < record_index)
  1282.     switch (record[r_index]) {
  1283.         case (LINEXY) :
  1284.         *(int *)(record + r_index + 2) += dh;
  1285.         *(int *)(record + r_index + 4) += dv;
  1286.         r_index += 6;
  1287.         break;
  1288.         case (MOVEXY) :
  1289.         *(int *)(record + r_index + 2) += dh;
  1290.         *(int *)(record + r_index + 4) += dv;
  1291.         r_index += 6;
  1292.         break;
  1293.         case (LABEL) :
  1294.         r_index += 3 + record[r_index + 2] + even_p(record[r_index + 2]);
  1295.         break;
  1296.         case (SETPENVIS) :
  1297.         r_index += 2;
  1298.         break;
  1299.         case (SETPENMODE) :
  1300.         r_index += 4;
  1301.         break;
  1302.         case (SETPENCOLOR) :
  1303.         r_index += 6;
  1304.         break;
  1305.         case (SETPENSIZE) :
  1306.         r_index += 6;
  1307.         break;
  1308.         case (SETPENPATTERN) :
  1309.         r_index += 10;
  1310.         break;
  1311.     }
  1312. */
  1313. }
  1314.