ftp.nice.ch/pub/next/unix/tools/jug.0.7.N.bs.tar.gz#/x11.c

This is x11.c in view mode; [Download] [Up]

/*  (c) 1991 S.Hawtin
   Permission is granted to make any use of this file provided
    1) It is not used for commercial gain without my permission
    2) This notice is included in all copies
    3) Altered copies are marked as such

  No liability is accepted for the contents of the file.

*/

/* Display a juggle on a simple X windows terminal */

/**********************************************************************/

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include <stdio.h>
#include <math.h>
#include "jug.h"

#define X_SCALE  0.3
#define Y_SCALE  0.2
#define X_OFFSET 170
#define Y_OFFSET 400
#define BALL_RADIUS 7
#define RETURN_X 250
#define RETURN_Y 450

int time_x = 50;
int time_y = RETURN_Y;
int ball_offset = 2*BALL_RADIUS/X_SCALE;

double x_scale = X_SCALE;
double y_scale = Y_SCALE;

static Display *x_display;
static Window  window;
static Pixmap  pixmap;
static GC      gc;
static Colormap cmap;
static int     bgCol,fgCol;
static int     width,height;
static int	is_mono;
/* Reset this flag if you do not like the animated person */
static int	animate = True;
static int	animate_mono = True;

static int ball_width  = BALL_RADIUS;
static int ball_height = BALL_RADIUS;

static XColor colours[] =
   {   {0, 0x0000, 0x0000, 0x0000},    /* black */
       {0, 0xffff, 0x0000, 0x0000},    /* red   */
       {0, 0x0000, 0xffff, 0x0000},    /* green */
       {0, 0x0000, 0x0000, 0xffff},    /* blue  */
       {0, 0xffff, 0xffff, 0x0000},    /* yellow */
       {0, 0xffff, 0x0000, 0xffff},    /* violet */
       {0, 0x0000, 0xcccc, 0xcccc},    /* cyan  */
       {0, 0xffff, 0xffff, 0xffff},    /* white */
       {0, 0x8000, 0x8000, 0x8000},    /* grey */
       {0, 0x9000, 0x4000, 0x2000},    /* brown */
       {0, 0xffff, 0x6000, 0x0000},    /* orange */
    };


static void
real_to_screen(x,y,z,screen_x,screen_y)
    int x,y,z;
    int *screen_x;
    int *screen_y;
   {/* Convert from real space to screen space assumes 2D screen !! */
    *screen_x = X_OFFSET + (int)(x_scale * x);
    *screen_y = Y_OFFSET - (int)(y_scale * y);
    }

static int key_in;
static int are_exposed = False;

static void
process_events(wait)
    int wait;
   {/* Process events from the event queue */
    XEvent event;
    int count;
    char str[10];
    KeySym key_sym;

    while(wait || XPending(x_display))
       {XNextEvent(x_display,&event);

        wait = False;
        switch(event.type)
           {case Expose:
                if(event.xexpose.count == 0)
                   {if(are_exposed)
                        XCopyArea(x_display,pixmap,window,gc,0,0,width,height,0,0);
                    are_exposed = True;
                    }
                break;
            case KeyPress:
                count = XLookupString(&event,str,10,&key_sym,NULL);
                key_in = process_key(str[0]);
                break;
            case MappingNotify: /* Process keyboard mapping changes */
                XRefreshKeyboardMapping(&event);
                break;
            case ButtonPress:
                /* Process the button */
                key_in = True;
                break;
            case ButtonRelease: case CirculateNotify: case DestroyNotify:
            case GravityNotify: case MapNotify:       case ReparentNotify:
            case UnmapNotify:   case CreateNotify:    case MotionNotify:
            case NoExpose:      case ConfigureNotify:
                break;
            default:
                printf("Event %d\n",event.type);
            }
        }
      
    }

void
screen_clr()
   {/* Called just before processing, clear the pixmap and flush the event queue */
    int x,y,cx,cy,t;

    process_events(False);

    /* Now clear the pixmap */
    XSetForeground(x_display,gc,bgCol);
    XFillRectangle(x_display,pixmap,gc,0,0,width,height);
    if(animate)
       {/* Draw the person */
        XSetForeground(x_display,gc,fgCol);
        real_to_screen(100,1000,0,&cx,&cy);
        real_to_screen(300,600,0,&x,&y);
        if(cx > x)
           {t = cx;
            cx = x;
            x = t;
            }
        if(cy > y)
           {t = cy;
            cy = y;
            y = t;
            }
        XDrawArc(x_display,pixmap,gc,cx,cy,x-cx,y-cy,0,360*64);
        real_to_screen(150,625,0,&x,&y);
        real_to_screen(-50,550,0,&cx,&cy);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        real_to_screen(250,625,0,&x,&y);
        real_to_screen(450,550,0,&cx,&cy);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        real_to_screen(-100,400,0,&cx,&cy);
        real_to_screen(0,550,0,&x,&y);
        if(cx > x)
           {t = cx;
            cx = x;
            x = t;
            }
        if(cy > y)
           {t = cy;
            cy = y;
            y = t;
            }
        XDrawArc(x_display,pixmap,gc,cx,cy,x-cx,y-cy,0,360*64);
        real_to_screen(-50,400,0,&cx,&cy);
        real_to_screen(50,-30,0,&x,&y);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        real_to_screen(0,-150,0,&cx,&cy);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        real_to_screen(500,400,0,&cx,&cy);
        real_to_screen(400,550,0,&x,&y);
        if(cx > x)
           {t = cx;
            cx = x;
            x = t;
            }
        if(cy > y)
           {t = cy;
            cy = y;
            y = t;
            }
        XDrawArc(x_display,pixmap,gc,cx,cy,x-cx,y-cy,0,360*64);
        real_to_screen(450,400,0,&cx,&cy);
        real_to_screen(350,-30,0,&x,&y);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        real_to_screen(400,-150,0,&cx,&cy);
        XDrawLine(x_display,pixmap,gc,cx,cy,x,y);
        }
    }

void
out_string(x,y,str)
    int x,y;
    char *str;
   {/* Put out the string at x,y */

    XSetForeground(x_display,gc,fgCol);
    XDrawString(x_display,pixmap,gc,x,y,str,strlen(str));
    }

void
screen_flush()
   {/* Put the current screen on to the terminal */
    XCopyArea(x_display,pixmap,window,gc,0,0,width,height,0,0);
    }

extern int step;
extern int delay;
extern int sub_div;

void
init_screen(argc,argv)
    int *argc;
    char **argv;
   {/* Open the connection to the screen, take the arguments that we want 
      out before the main program gets to them */
    char title[128];
    XSizeHints props;
    int count,depth;

    /* Set the defaulst to look good on X screens */
    step = 1; delay = 0; sub_div = 10;

    if ((x_display = XOpenDisplay("")) == NULL)
       {fprintf(stderr,"Cannot connect to X server\n");
        exit(20);
        }
    bgCol = WhitePixel(x_display,DefaultScreen(x_display));
    fgCol = BlackPixel(x_display,DefaultScreen(x_display));

    width = height = 500;
    window = XCreateSimpleWindow(x_display,DefaultRootWindow(x_display),0,0,
                                 width,height,3,fgCol,bgCol);

    props.min_width = props.max_width = width;
    props.min_height = props.max_height = height;
    props.flags = PMinSize | PMaxSize;
    sprintf(title,"X11 %s %d.%d",NAME,MAJ_VERSION,MIN_VERSION);
    /* Fix from Steve Trainoff */
    XSetStandardProperties(x_display,window,title,title,None,argv,*argc,&props);
    pixmap = XCreatePixmap(x_display,DefaultRootWindow(x_display),width,height,
                           DefaultDepth(x_display,0));
    gc = XCreateGC(x_display,window,0,0);

    XSelectInput(x_display,window,
                   PointerMotionMask | ButtonPressMask | KeyPressMask |
	           ButtonReleaseMask | ExposureMask    | StructureNotifyMask);
    XMapWindow(x_display,window);
    /* Get the colours that we need */
    depth = DisplayPlanes(x_display,DefaultScreen(x_display));
    if(depth == 1)
        is_mono = True;
      else
       {is_mono = False;

        cmap = DefaultColormap(x_display,DefaultScreen(x_display));
        for(count=0;count<arraysize(colours);++count)
           {/* Get the colour */
            colours[count].flags = DoRed | DoGreen | DoBlue;
            XAllocColor(x_display,cmap,&colours[count]);
            }
        }
    /* Wait for our first expose event */
    while(!are_exposed)
        process_events(True);
    }

int
is_option(num,argv,argc)
    int *num;
    char **argv;
    int argc;
   {/* Process some option for the grapics */
    if(argv[*num][0] == '-')
       {switch(argv[*num][1])
           {case 'm': case 'M':
                is_mono = True;
                return(1);
            case 'a': case 'A':
                animate = False;
                animate_mono = False;
                return(1);
            case 'c': case 'C':
                animate_mono = False;
                return(1);
            }
        }

    /* Not a valid graphics option */

    /* Tell the user the options */
    printf("Graphics options\n");
    printf("          -m -a -c\n");
    return(0);
    }

void
tidy_screen()
   {/* Tidy up the screen connection */
    XFreeGC(x_display,gc);
    XFreePixmap(x_display,pixmap);
    XDestroyWindow(x_display,window);
    XCloseDisplay(x_display);
    }

void
rescale()
   {/* The program is rescalling the screen */
    ball_width = (BALL_RADIUS*x_scale)/X_SCALE;
    ball_height = (BALL_RADIUS*y_scale)/Y_SCALE;
    }

/***********************************************************************/

/* This portion converts the current position into an image on the 
   screen */

void
draw_ball(x,y,z,ball)
    int x,y,z;
    Ball *ball;
   {/* Draw a ball ont the pixmap */
    int s_x,s_y;

    real_to_screen(x,y,z,&s_x,&s_y);
    if(is_mono)
       {/* On a monochrome screen we should put a letter in the ball, or 
          something */
        char str[2];

        XSetForeground(x_display,gc,fgCol);
        XFillArc(x_display,pixmap,gc,s_x-ball_width,s_y-ball_height,
                       2*ball_width,2*ball_height,0,360*64);
        XSetForeground(x_display,gc,bgCol);
        str[0] = ball->alias[0];
        str[1] = '\0';
        XDrawString(x_display,pixmap,gc,s_x-ball_width/3,s_y,str,strlen(str));
        }
      else
       {/* A colour screen */
        XSetForeground(x_display,gc,colours[ball->ball_num].pixel);
        XFillArc(x_display,pixmap,gc,s_x-ball_width,s_y-ball_height,
                       2*ball_width,2*ball_height,0,360*64);
        }
    }

#define FORE_LENGTH 425
#define LOWER_LENGTH 450

static void
draw_arm(x,y,z,hand)
    int x,y,z;
    Hand *hand;
   {/* Draw the arm */
    int x1,y1,z1,x2,y2,z2,d2;
    int cx,cy,dx,dy;

    /* Where is the top of this arm? */
    z1 = -450;y1 = 475;
    if(hand->def_x == 0)
        x1 = -50;
      else
        x1 = 450;
    /* Assume that the complete arm is held in a vertical plane */
    /* There must be a simple way to work out where the elbow is! */

    /* How far away is the hand from the shoulder? */
    d2 = (x - x1)*(x - x1) + (y - y1)*(y - y1) + (z - z1)*(z - z1);
    if(d2 < (FORE_LENGTH-LOWER_LENGTH)*(FORE_LENGTH-LOWER_LENGTH) ||
       d2 > (FORE_LENGTH+LOWER_LENGTH)*(FORE_LENGTH+LOWER_LENGTH))
       {/* The arm cannot reach there !! */
        x2 = x1; y2 = y1; z2 = z1;
        }
      else
       {/* Work out the angles */
        double a1,a2,delta_y,delta_x;

        a1 = asin((double)(y1-y)/sqrt((double)d2));
        a1 += acos((double)(FORE_LENGTH*FORE_LENGTH + d2 - LOWER_LENGTH*LOWER_LENGTH)/
                           (2.0*FORE_LENGTH*sqrt((double)d2)));
        delta_y = sin(a1)*FORE_LENGTH;
        delta_x = cos(a1)*FORE_LENGTH;
        y2 = y1 - delta_y;
        x2 = x1 - (int)((delta_x * (x1 - x))/sqrt((double)((x - x1)*(x - x1) + 
                                                           (z - z1)*(z - z1))));
        z2 = z1 - (int)((delta_x * (z1 - z))/sqrt((double)((x - x1)*(x - x1) + 
                                                           (z - z1)*(z - z1))));
        }

    real_to_screen(x-50,y,z,&cx,&cy);
    real_to_screen(x2-50,y2,z2,&dx,&dy);
    XDrawLine(x_display,pixmap,gc,cx,cy,dx,dy);
    real_to_screen(x1-50,y1,z1,&cx,&cy);
    XDrawLine(x_display,pixmap,gc,cx,cy,dx,dy);

    real_to_screen(x+50,y,z,&cx,&cy);
    real_to_screen(x2+50,y2,z2,&dx,&dy);
    XDrawLine(x_display,pixmap,gc,cx,cy,dx,dy);
    real_to_screen(x1+50,y1,z1,&cx,&cy);
    XDrawLine(x_display,pixmap,gc,cx,cy,dx,dy);
    }

void
draw_hand(x,y,z,hand)
    int x,y,z;
    Hand *hand;
   {/* Draw a hand out, for the moment just a half box */
    int s_x,s_y;

    real_to_screen(x,y,z,&s_x,&s_y);
    if(is_mono || animate_mono)
       {
        XSetForeground(x_display,gc,fgCol);
        }
      else
       {/* The hand colour depends on which hand */
        XSetForeground(x_display,gc,colours[hand->hand_num].pixel);
        }
    if(animate)
        draw_arm(x,y,z,hand);
      else if (is_mono)
       {char str[2];
        str[0] = hand->alias[0];
        str[1] = '\0';
        XDrawString(x_display,pixmap,gc,s_x-ball_width/3,s_y+2*ball_height,str,strlen(str));
        }
    XDrawLine(x_display,pixmap,gc,s_x-3*ball_width,s_y,
                                  s_x-3*ball_width,s_y+ball_height);
    XDrawLine(x_display,pixmap,gc,s_x-3*ball_width,s_y+ball_height,
                                  s_x+3*ball_width,s_y+ball_height);
    XDrawLine(x_display,pixmap,gc,s_x+3*ball_width,s_y+ball_height,
                                  s_x+3*ball_width,s_y);
    }

void
wait_step()
   {/* Wait for the user to do something before going on */
    char next;

    out_string(RETURN_X,RETURN_Y,"press <Return> or <?>");

    /* Now display the screen we have constructed */
    screen_flush();

    /* Wait for a character */
    key_in = False;
    do {
        process_events(True);
        } while (!key_in);
    }

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.