home *** CD-ROM | disk | FTP | other *** search
/ BMUG PD-ROM 1995 Fall / PD-ROM F95.toast / Programming / Programming Languages / UCB Logo 3.0 ƒ / sources / standard source / graphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-14  |  26.0 KB  |  1,283 lines  |  [TEXT/ttxt]

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