/***************************************/ /* View 1.0 */ /* */ /* Threaded X-window 2D Object Group */ /* Animator. */ /* */ /* Ju Li Nov.26 1998 MIT */ /***************************************/ /* Version Notes: 1.0 -- Multiple displays; Threaded animation (not available on Linux); Instance by signal; */ #include "V.h" #define DEFAULT_FACTOR (0.01) #define key_verify(a,b,c) (b==(a)c) struct OGL { char token[V_MAX_OG_TOKEN_SIZE]; int obj_type; int n; /* number of objects in group */ void *gp; /* group array pointer */ struct OGL *next; }; /** The scope of following is within **/ static volatile double (*H)[2]; static volatile Bool active[V_MAXWINDOW], LockOGL, OGLRendered[V_MAXWINDOW], PBC[V_MAXWINDOW]; /* the only bit needed to be preset for the Animator */ static Bool A_never_entered = True; /* the above can be modified by the main */ /* thread without notice, thus volatile. */ static pid_t master_pid; static struct OGL oglpool[V_MAX_NUM_OGS]={0}; static char display_address[V_MAXWINDOW][V_MAX_STRLEN], title[V_MAXWINDOW][V_MAX_STRLEN]; static Display *display[V_MAXWINDOW]; static int screen[V_MAXWINDOW]; static Window root[V_MAXWINDOW],windows[V_MAXWINDOW]; static XSizeHints win[V_MAXWINDOW]; static unsigned long foreground[V_MAXWINDOW], background[V_MAXWINDOW], nanim[V_MAXWINDOW]; static GC gc[V_MAXWINDOW]; static Pixmap pixmap[V_MAXWINDOW]; static unsigned int border_width[V_MAXWINDOW], color_depth[V_MAXWINDOW], mask[V_MAXWINDOW], xpm_counter[V_MAXWINDOW]; static Colormap colormap[V_MAXWINDOW]; static XColor color[V_MAXWINDOW][V_MAXCOLOR]; static int x[V_MAXWINDOW], y[V_MAXWINDOW], px[V_MAXWINDOW], py[V_MAXWINDOW], lx[V_MAXWINDOW], ly[V_MAXWINDOW]; static double unit[V_MAXWINDOW], w[V_MAXWINDOW][2], A[V_MAXWINDOW][2][2], ws[V_MAXWINDOW][2], rate[V_MAXWINDOW], timespent[V_MAXWINDOW], factor[V_MAXWINDOW], dws[V_MAXWINDOW][2]; static const char *Vcolorname[V_MAXCOLOR]= {"black", "red", "green", "blue", "cyan", "magenta", "yellow", "white"}; /* internal functions */ static void thread_start (void *iw_pointer); static void Animate (int iw); static Bool treatevent (int iw, XEvent *e); static void rw2s (int iw, double rw[2], double s[2]); static Bool s2screen (int iw, double s[2]); static void setfg (int iw, int cid); static void setLA (int iw, int cid); static Bool box_clip_line (double x0,double y0,double width,double height,double xx[4]); static void Draw_LINE (int iw, int cid, int xx[4]); static void Render_LINE (int iw, int n, VLINE gp[]); static Bool window_clip_circle (int iw, int x, int y, int r); static void Render_POINT (int iw, int n, VPOINT gp[]); static void Render_CIRCLE(int iw, int n, VCIRCLE gp[]); static void SignIn (volatile double h[2][2]); static void signal_handler_thread (void *a); static void SignOut (); /** this program: internal use only **/ /* Animators are not allowed to render when */ /* the OG is being modified by main thread. */ void VLock() { LockOGL = True; return; } /* end VLock() */ /* Unlock when done and clean the slates */ void VUnLock() { int i; LockOGL = False; for (i=0; i0 solid, <0 dash */ void setLA (int iw, int cid) { static int lastLA[V_MAXWINDOW]={0}; if ( lastLA[iw] * cid <= 0 ) { if ( cid > 0 ) XSetLineAttributes (display[iw], gc[iw], 1, LineSolid, CapButt, JoinMiter); else if ( cid < 0 ) XSetLineAttributes (display[iw], gc[iw], 1, LineOnOffDash, CapButt, JoinMiter); else { printf ("setLA(): cid = 0 illegal.\n"); exit(1); } lastLA[iw] = cid; } return; } /* end setLA() */ #define inside_box(width,height,x,y) \ (((x)*(x-(width))<=V_TINY)&&((y)*(y-(height))<=V_TINY)) /* clip line (xx[0],xx[1])-(xx[2],xx[3]) */ /* by rectangle (x0,y0)+(width,height). */ Bool box_clip_line (double x0, double y0, double width, double height, double xx[4]) { int i, j, m, n; double dir[2], c[6], cc, dd; Bool A, B; A = inside_box(width,height,xx[0]-x0,xx[1]-y0); B = inside_box(width,height,xx[2]-x0,xx[3]-y0); if (A&&B) return (True); dir[0] = xx[2]-xx[0]; dir[1] = xx[3]-xx[1]; /* distances of vertices to the line */ c[0] = (x0-xx[0])*(-dir[1])+(y0-xx[1])*dir[0]; c[1] = (x0+width-xx[0])*(-dir[1])+(y0-xx[1])*dir[0]; c[2] = (x0-xx[0])*(-dir[1])+(y0+height-xx[1])*dir[0]; c[3] = (x0+width-xx[0])*(-dir[1])+(y0+height-xx[1])*dir[0]; /* see if the segment lies within the window */ if ((c[0]*c[1]>0)&&(c[0]*c[2]>0)&&(c[0]*c[3]>0)) return (False); dd = sqrt(dir[0]*dir[0]+dir[1]*dir[1]); if (dd==0) return (False); dir[0] /= dd; dir[1] /= dd; if ( fabs(xx[2]-xx[0]) < V_TINY ) { c[2] = (y0+height-xx[1])*dir[1]; c[3] = (y0-xx[1])*dir[1]; m = 4; } else if ( fabs(xx[3]-xx[1]) < V_TINY ) { c[2] = (x0-xx[0])*dir[0]; c[3] = (x0+width-xx[0])*dir[0]; m = 4; } else { cc = 1+dir[1]*dir[1]/dir[0]/dir[0]; c[2] = (x0-xx[0])*dir[0]*cc; c[3] = (x0+width-xx[0])*dir[0]*cc; cc = 1+dir[0]*dir[0]/dir[1]/dir[1]; c[4] = (y0+height-xx[1])*dir[1]*cc; c[5] = (y0-xx[1])*dir[1]*cc; m = 6; } for (n=i=2; i-100*V_TINY)&& inside_box(width,height,xx[0]+c[i]*dir[0]-x0, xx[1]+c[i]*dir[1]-y0)) c[n++] = c[i]; if (A) { xx[2] = xx[0] + c[2]*dir[0]; xx[3] = xx[1] + c[2]*dir[1]; } else if (B) { xx[0] += c[2]*dir[0]; xx[1] += c[2]*dir[1]; } else { if (n!=4) return(False); if (c[2]>c[3]) {cc=c[3];dd=c[2];} else {cc=c[2];dd=c[3];} xx[2] = xx[0] + dd*dir[0]; xx[3] = xx[1] + dd*dir[1]; xx[0] += cc*dir[0]; xx[1] += cc*dir[1]; } return (True); } /* end windowclip() */ /* Draw a line on the window with automatic window clipping */ #define TEST_LINE_CLIPPING void Draw_LINE (int iw, int cid, int x[4]) { double xx[4]; xx[0]=x[0]; xx[1]=x[1]; xx[2]=x[2]; xx[3]=x[3]; if ( box_clip_line(0,0,win[iw].width,win[iw].height,xx) ) { setfg (iw, cid); setLA (iw, cid); XDrawLine (display[iw], pixmap[iw], gc[iw], rint(xx[0]), rint(xx[1]), rint(xx[2]), rint(xx[3])); #ifdef TEST_LINE_CLIPPING if ( (xx[0]!=x[0]) || (xx[1]!=x[1]) ) { setfg (iw, V_RED); setLA(iw, 1); XDrawArc (display[iw], pixmap[iw], gc[iw], rint(xx[0])-5, rint(xx[1])-5, 10, 10, 0, 360*64); } if ( (xx[2]!=x[2]) || (xx[3]!=x[3]) ) { setfg (iw, V_RED); setLA(iw, 1); XDrawArc (display[iw], pixmap[iw], gc[iw], rint(xx[2])-5, rint(xx[3])-5, 10, 10, 0, 360*64); } #endif } return; } /* end Draw_LINE() */ /* convert reduced rw[] coordinates to s[] */ void rw2s (int iw, double rw[2], double s[2]) { double cc, HI[2][2]; cc = H[0][0]*H[1][1]-H[0][1]*H[1][0]; HI[0][0] = H[1][1]/cc; HI[0][1] = -H[0][1]/cc; HI[1][0] = -H[1][0]/cc; HI[1][1] = H[0][0]/cc; s[0] = unit[iw]*(rw[0]*HI[0][0]+rw[1]*HI[1][0]); s[1] = unit[iw]*(rw[0]*HI[0][1]+rw[1]*HI[1][1]); if ( PBC[iw] ) { while (s[0]<0) s[0]++; while (s[0]>1) s[0]--; while (s[1]<0) s[1]++; while (s[1]>1) s[1]--; rw[0]=(s[0]*H[0][0]+s[1]*H[1][0])/unit[iw]; rw[1]=(s[0]*H[0][1]+s[1]*H[1][1])/unit[iw]; } return; } /* end rw2s() */ /* s -> X, only one copy of the objects about ws[]+-0.5 */ Bool s2screen (int iw, double s[2]) { double sc[2], sr[2]; dws[iw][0] = s[0]-ws[iw][0]; dws[iw][1] = s[1]-ws[iw][1]; if ( PBC[iw] ) { while (dws[iw][0]<-0.5) dws[iw][0]++; while (dws[iw][0]>0.5) dws[iw][0]--; while (dws[iw][1]<-0.5) dws[iw][1]++; while (dws[iw][1]>0.5) dws[iw][1]--; } sc[0] = (dws[iw][0]*H[0][0]+dws[iw][1]*H[1][0])/unit[iw]; sc[1] = (dws[iw][0]*H[0][1]+dws[iw][1]*H[1][1])/unit[iw]; /* readings in window axes */ sr[0] = A[iw][0][0]*sc[0]+A[iw][0][1]*sc[1]; sr[1] = A[iw][1][0]*sc[0]+A[iw][1][1]*sc[1]; x[iw] = rint(win[iw].width/2.+sr[0]*V_RESOLUTION); y[iw] = rint(win[iw].height/2.-sr[1]*V_RESOLUTION); return(inside_box(win[iw].width,win[iw].height,x[iw],y[iw])); } /* end s2screen() */ /* activated by Up/Down/Left/Right events */ void translate_window (int iw, int i, double delta) { if ( PBC[iw] ) { w[iw][0] = (ws[iw][0]*H[0][0]+ ws[iw][1]*H[1][0])/unit[iw]; w[iw][1] = (ws[iw][0]*H[0][1]+ ws[iw][1]*H[1][1])/unit[iw]; } w[iw][0] += delta * A[iw][i][0]; w[iw][1] += delta * A[iw][i][1]; rw2s (iw, &w[iw][0], &ws[iw][0]); return; } /* end translate_window() */ #define min_motion 3 void rotate_window (int iw, int to_x, int to_y) { int i, j; double a[2], b[2], ca[2], cb[2], g[2], cc; if ((to_x-lx[iw])*(to_x-lx[iw]) + (to_y-ly[iw])*(to_y-ly[iw]) < min_motion*min_motion) return; /* stuffs seem to rotate from a[] */ a[0] = lx[iw]-win[iw].width/2.; a[1] = -ly[iw]+win[iw].height/2.; cc = sqrt(a[0]*a[0]+a[1]*a[1]); if ( cc<=min_motion ) return; a[0] /= cc; a[1] /= cc; /* to b[] in the viewport, */ b[0] = to_x-win[iw].width/2.; b[1] = -to_y+win[iw].height/2.; cc = sqrt(b[0]*b[0]+b[1]*b[1]); if ( cc<=min_motion ) return; b[0] /= cc; b[1] /= cc; /* equivalent to rotate the VIEWPORT from b to a */ ca[0] = -a[1]; ca[1] = a[0]; cb[0] = -b[1]; cb[1] = b[0]; g[0] = A[iw][0][0]*b[0] +A[iw][0][1]*b[1]; g[1] = A[iw][0][0]*cb[0]+A[iw][0][1]*cb[1]; /* b->a, cb->ca */ A[iw][0][0] = g[0]*a[0]+g[1]*ca[0]; A[iw][0][1] = g[0]*a[1]+g[1]*ca[1]; A[iw][1][0] = -A[iw][0][1]; A[iw][1][1] = A[iw][0][0]; /* save pointer motion */ lx[iw] = to_x; ly[iw] = to_y; return; } /* end rotate_window() */ /* PBC: render a physical bonding between the two points */ void Render_LINE (int iw, int n, VLINE gp[]) { int i, xx[4], zz[4]; double sw[4], ss[4], ds[2], s[4], sc[2], dx[2]; for (i=0; i0.5) ds[0]--; while (ds[0]<-0.5) ds[0]++; while (ds[1]>0.5) ds[1]--; while (ds[1]<-0.5) ds[1]++; ss[0] = sw[0]; ss[1] = sw[1]; ss[2] = ss[0]+ds[0]; ss[3] = ss[1]+ds[1]; /* clip it by +-0.5 */ box_clip_line (-0.5,-0.5,1,1,ss); sc[0] = (ss[2]-sw[0])*H[0][0]+(ss[3]-sw[1])*H[1][0]; sc[1] = (ss[2]-sw[0])*H[0][1]+(ss[3]-sw[1])*H[1][1]; dx[0] = rint((sc[0]*A[iw][0][0]+sc[1]*A[iw][0][1])/ unit[iw]*V_RESOLUTION); dx[1] = rint((sc[0]*A[iw][1][0]+sc[1]*A[iw][1][1])/ unit[iw]*V_RESOLUTION); zz[0]=xx[0]; zz[1]=xx[1]; zz[2]=zz[0]+rint(dx[0]); zz[3]=zz[1]-rint(dx[1]); Draw_LINE (iw, gp[i].cid, zz); if ((abs(zz[2]-xx[2])>1)||(abs(zz[3]-xx[3])>1)) { ss[0] = sw[2]; ss[1] = sw[3]; ss[2] = ss[0]-ds[0]; ss[3] = ss[1]-ds[1]; box_clip_line (-0.5,-0.5,1,1,ss); sc[0] = (ss[2]-sw[2])*H[0][0]+(ss[3]-sw[3])*H[1][0]; sc[1] = (ss[2]-sw[2])*H[0][1]+(ss[3]-sw[3])*H[1][1]; dx[0] = rint((sc[0]*A[iw][0][0]+sc[1]*A[iw][0][1])/ unit[iw]*V_RESOLUTION); dx[1] = rint((sc[0]*A[iw][1][0]+sc[1]*A[iw][1][1])/ unit[iw]*V_RESOLUTION); zz[0]=xx[2]; zz[1]=xx[3]; zz[2]=zz[0]+rint(dx[0]); zz[3]=zz[1]-rint(dx[1]); Draw_LINE (iw, gp[i].cid, zz); } } else Draw_LINE (iw, gp[i].cid, xx); } return; } /* end Render_LINE() */ Bool window_clip_circle (int iw, int x, int y, int r) { return(inside_box(win[iw].width,win[iw].height,x-r,y-r) || inside_box(win[iw].width,win[iw].height,x-r,y+r) || inside_box(win[iw].width,win[iw].height,x+r,y-r) || inside_box(win[iw].width,win[iw].height,x+r,y+r) ); } /* end window_clip_circle() */ /* Draw a circle on the window with automatic clipping */ void Draw_CIRCLE (int iw, int x, int y, int a, int cid) { setfg (iw, cid); if ((a==1) && inside_box(win[iw].width,win[iw].height,x,y)) XDrawPoint(display[iw], pixmap[iw], gc[iw], x, y); else if ((a==2)&&window_clip_circle(iw,x,y,1)) { XDrawPoint(display[iw], pixmap[iw], gc[iw], x+1, y); XDrawPoint(display[iw], pixmap[iw], gc[iw], x-1, y); XDrawPoint(display[iw], pixmap[iw], gc[iw], x, y+1); XDrawPoint(display[iw], pixmap[iw], gc[iw], x, y-1); if (cid > 0) XDrawPoint(display[iw], pixmap[iw], gc[iw], x, y); } else if (window_clip_circle(iw,x,y,a)) { /* draw solid circle */ setLA (iw, 1); if (cid > 0) XFillArc(display[iw], pixmap[iw], gc[iw], x-a, y-a, a*2, a*2, 0, 360*64); else XDrawArc(display[iw], pixmap[iw], gc[iw], x-a, y-a, a*2, a*2, 0, 360*64); } return; } /* end Draw_CIRCLE() */ void Render_POINT (int iw, int n, VPOINT gp[]) { int i; VLINE line[1]; for (i=0; inext!=NULL; p=p->next) switch (p->next->obj_type) { case V_POINT: Render_POINT(iw, p->next->n, (VPOINT*)(p->next->gp)); break; case V_LINE: Render_LINE(iw, p->next->n, (VLINE*)(p->next->gp)); break; case V_CIRCLE: Render_CIRCLE(iw, p->next->n, (VCIRCLE*)(p->next->gp)); break; default: printf ("obj_type %d does not exist.\n", p->next->obj_type); exit(1); } XCopyArea (display[iw], pixmap[iw], windows[iw], gc[iw], 0, 0, win[iw].width, win[iw].height, 0, 0); /* synchronize with the server without */ /* discarding events in the event queue */ XSync (display[iw], False); OGLRendered[iw] = True; nanim[iw]++; /* dynamic tuning of refresh rate */ gettimeofday (&tp, NULL); rendertime = tp.tv_sec+0.000001*tp.tv_usec-inittime; timespent[iw] += (rendertime>1./rate[iw])?rendertime:1./rate[iw]; } if ( 1./rate[iw] > rendertime ) waitfor( 1./rate[iw] - rendertime ); } } /* end Animate() */ /* capture the screen in ASCII xpm format */ int capture_xpm (int iw) { char filename[2*V_MAX_STRLEN], *p, *q; sprintf (filename, "%s_%d.xpm", &title[iw][0], xpm_counter[iw]++); /* fill white space by underline */ for (q=filename; (*q!=(char)0); q++) if ((*q==' ')||(*q=='\t')) *q = '_'; printf("\nSave screen %d on (default=\"%s\"): ", iw, filename); for (p=q; p0.0005 <2>0.001 <3>0.002 <4>0.005 <5>0.01\n"); printf("<6>0.02 <7>0.05 <8>0.1 <9>0.25 <0>default\n\n"); printf("F1: help\n"); printf("F2: print out status of this window\n"); printf("F3: clone this window\n"); printf("F4: generate a default window\n"); printf("F5: restore collinear axes\n"); printf("F6: dump screen-shot to .xpm file\n"); printf("F9: toggle PBC\n"); printf("ESC: close this window\n"); printf("q: close all windows\n\n"); printf("If no window exists, create a new one by\n"); printf("%% kill -%d %d\n", V_SIGNAL, (int)master_pid); printf("****************************************************\n"); return; } /* end print_help() */ /* Event-handler of the Animator */ Bool treatevent (int iw, XEvent *e) { static long last_button_press_time[V_MAXWINDOW] = {0}; int a, b; Bool c; XSizeHints newhint; Window root_return, child_return; c = XQueryPointer (display[iw], windows[iw], &root_return, &child_return, &a, &b, &px[iw], &py[iw], &mask[iw]); switch ( e->type ) { case ButtonPress: if ( e->xbutton.time - last_button_press_time[iw] < V_DEFAULT_DBLE_CLICK_IN_MS ) { /* double click event */ translate_window(iw,0,(px[iw]-win[iw].width/2.)/V_RESOLUTION); translate_window(iw,1,(-py[iw]+win[iw].height/2.)/V_RESOLUTION); XWarpPointer (display[iw], windows[iw], None, 0, 0, 0, 0, -px[iw]+win[iw].width/2, -py[iw]+win[iw].height/2); last_button_press_time[iw] = -V_HUGE; return (True); } else { lx[iw]=px[iw]; ly[iw]=py[iw]; last_button_press_time[iw] = e->xbutton.time; return (False); } case ButtonRelease: case MotionNotify: rotate_window (iw, px[iw], py[iw]); return (True); case Expose: XGetGeometry (display[iw], windows[iw], &root[iw], &newhint.x, &newhint.y, (unsigned *) &newhint.width, (unsigned *) &newhint.height, &border_width[iw], &color_depth[iw] ); win[iw].width--; win[iw].height--; win[iw].x = newhint.x; win[iw].y = newhint.y; if ( (newhint.width!=win[iw].width) || (newhint.height!=win[iw].height) ) { /* the window has been resized */ /* old pixmap cannot be used */ XFreeGC (display[iw], gc[iw]); XFreePixmap (display[iw], pixmap[iw]); win[iw].width = newhint.width; win[iw].height = newhint.height; pixmap[iw] = XCreatePixmap ( display[iw], root[iw], win[iw].width, win[iw].height, color_depth[iw] ); gc[iw] = XCreateGC(display[iw],pixmap[iw],0,0); } return (True); case KeyPress: if (!c) return (False); switch (XKeycodeToKeysym (display[iw], e->xkey.keycode, 0)) { case XK_F1: print_help(iw); return (False); case XK_F2: print_status(iw); return (False); case XK_F3: translate_window(iw,0,0); VAddWindow (display_address[iw], "V_DEFAULT", H, unit[iw], w[iw][0], w[iw][1], A[iw][0][0], A[iw][0][1], (double)win[iw].width/V_RESOLUTION, (double)win[iw].height/V_RESOLUTION, rate[iw]); return (False); case XK_F4: VAddDefaultWindow(H); return (False); case XK_F5: A[iw][0][0]=1; A[iw][0][1]=0; A[iw][1][0]=0; A[iw][1][1]=1; return (True); case XK_F6: capture_xpm(iw); return (False); case XK_F9: VSetPBC(iw,!PBC[iw]); return (True); case XK_Escape: VCloseWindow(iw); return (False); case XK_q: VCloseAllWindows(); return (False); case XK_Left: translate_window(iw,0,factor[iw]);return(True); case XK_Right: translate_window(iw,0,-factor[iw]);return(True); case XK_Down: translate_window(iw,1,factor[iw]); return(True); case XK_Up: translate_window(iw,1,-factor[iw]); return(True); case XK_Page_Up: unit[iw] /= (1+factor[iw]); if ( !PBC[iw] ) { w[iw][0]*=(1+factor[iw]); w[iw][1]*=(1+factor[iw]); } return(True); case XK_Page_Down: unit[iw] *= (1+factor[iw]); if ( !PBC[iw] ) { w[iw][0]/=(1+factor[iw]); w[iw][1]/=(1+factor[iw]); } return(True); case XK_1: factor[iw]=0.0005; return(False); case XK_2: factor[iw]=0.001; return(False); case XK_3: factor[iw]=0.002; return(False); case XK_4: factor[iw]=0.005; return(False); case XK_5: factor[iw]=0.01; return(False); case XK_6: factor[iw]=0.02; return(False); case XK_7: factor[iw]=0.05; return(False); case XK_8: factor[iw]=0.1; return(False); case XK_9: factor[iw]=0.25; return(False); case XK_0: factor[iw]=DEFAULT_FACTOR; return(False); default: return (False); } default: return (False); } } /* end treatevent() */ /* SignIn() and SignOut() handle animator birth and death */ void SignIn (volatile double h[2][2]) { int i; if ( A_never_entered ) { H = h; printf("\n==============================================\n"); printf("V ver %.1f signing in (Ju Li, liju99@mit.edu).\n", V_VERSION); printf("==============================================\n\n"); A_never_entered = False; for (i=0; i= V_MAX_STRLEN) || (strlen(vtitle) >= V_MAX_STRLEN) ) { printf ("V_MAX_STRLEN = %d reached (see \"v.h\").\n", V_MAX_STRLEN); exit(1); } /* store the TCP/IP X connection address */ strcpy (&display_address[iw][0], address); if (!strcasecmp(&display_address[iw][0], "V_DEFAULT")) strcpy (&display_address[iw][0], getenv("DISPLAY")); /* store the window title name */ strcpy (&title[iw][0], vtitle); if (!strcasecmp(&title[iw][0], "V_DEFAULT")) sprintf (&title[iw][0], "win %d", iw); /* how much rs length is 1 render world (rw) unit */ unit[iw] = vunit; /* where to put the window */ w[iw][0] = vwx; w[iw][1] = vwy; rw2s (iw, &w[iw][0], &ws[iw][0]); /* what is the window x-axes in rw */ cc = sqrt(vxx*vxx+vxy*vxy); A[iw][0][0] = vxx / cc; A[iw][0][1] = vxy / cc; A[iw][1][0] = -A[iw][0][1]; A[iw][1][1] = A[iw][0][0]; /* set X properties */ win[iw].width = ceil(vwidth*V_RESOLUTION); win[iw].height = ceil(vheight*V_RESOLUTION); win[iw].flags = PSize; /* factor of change */ factor[iw] = DEFAULT_FACTOR; /* pictures per second */ rate[iw] = key_verify(double,vrefreshrate,V_DEFAULT)? V_DEFAULT_REFRESHRATE:vrefreshrate; active[iw] = True; PBC[iw] = True; xpm_counter[iw] = 0; nanim[iw]=1; timespent[iw]=1/rate[iw]; /* spawn a thread to animate and handle events */ pthread_create (&tid, NULL, (void *(*)(void *)) thread_start, (void *)(&iw)); return (iw); } /* end VAddWindow() */ int VAddDefaultWindow (volatile double h[2][2]) { double det, length; det = h[0][0]*h[1][1]-h[0][1]*h[1][0]; length = sqrt(fabs(det)); return(VAddWindow("V_DEFAULT", /* DISPLAY as xhost */ "V_DEFAULT", /* win title name */ h, /* metric of rs */ length, /* rs->rw unit cov */ /* viewport at center */ 0.5*(h[0][0]+h[1][0])/length, 0.5*(h[0][1]+h[1][1])/length, 1., 0., /* x-axis same as rw */ /* screen contains box */ (fabs(h[0][0])+fabs(h[1][0]))/length, (fabs(h[0][1])+fabs(h[1][1]))/length, V_DEFAULT /* animation frames/second */ )); } /* end VAddDefaultWindow() */ void VCloseWindow (int iw) { int i; Bool one_active = False; active[iw] = False; for (i=0; iV_MAX_OG_TOKEN_SIZE-1) { printf ("token %s should be less than %d bytes long.\n", token, V_MAX_OG_TOKEN_SIZE); exit(1); } /* root node is oglpool[0] */ for ( p = oglpool; (p->next != NULL) && strncmp(p->next->token, token, V_MAX_OG_TOKEN_SIZE-1); p = p->next ); if ( p->next == NULL ) { /* look for free space */ for ( q = oglpool+1; q < oglpool+V_MAX_NUM_OGS; q++ ) if ( *(q->token)==(char)0 ) { p->next = q; q->next = NULL; strcpy (q->token, token); q->obj_type = obj_type; q->n = n; q->gp = (void *) malloc (n*V_OBJ_SIZE(obj_type)); /* set defaults to 0 */ memset (q->gp, 0, n*V_OBJ_SIZE(obj_type)); return (q->gp); } printf ("error: oglpool %d records all used up.\n", V_MAX_NUM_OGS-1); exit(1); } else { printf("error: OG token name \"%s\" already used.\n", token); exit(1); } return (NULL); } /* VCreateOG() */ void *VGetOG (char token[]) { struct OGL *p; for ( p = oglpool; (p->next != NULL) && strncmp(p->next->token, token, V_MAX_OG_TOKEN_SIZE-1); p = p->next); if ( p->next == NULL ) { printf("error: OG token name \"%s\" not found.\n", token); exit(1); } else return (p->next->gp); return (NULL); } /* VGetOG() */ void VDeleteOG (char token[]) { struct OGL *p; /* destroy this record and free resources */ for ( p = oglpool; (p->next != NULL) && strncmp(p->next->token, token, V_MAX_OG_TOKEN_SIZE-1); p = p->next); if ( p->next == NULL ) { printf("error: token name \"%s\" not found.\n", token); exit(1); } else { free (p->next->gp); *(p->next->token) = (char)0; p->next = p->next->next; return; } } /* VDeleteOG() */ #ifndef _NO_V_TEST void *colorful (char name[], int n) { int i; VCIRCLE *circles; VLock(); circles = (VCIRCLE *) VCreateOG (name, V_CIRCLE, n); for (i=0; i0.5) circles[i].cid = -circles[i].cid; } VUnLock(); return((void *)circles); } void *box (char *name) { VPOINT *box; VLock(); box = (VPOINT *) VCreateOG(name, V_POINT, 4); /* everything is by default 0, so */ box[0].s[0] = 0.3; box[0].s[1] = 0.3; box[0].size=1; box[0].cid=V_GREEN; box[1].s[0] = 0.7; box[1].s[1] = 0.3; box[1].size=1; box[1].cid=V_GREEN; box[2].s[0] = 0.7; box[2].s[1] = 0.7; box[2].size=1; box[2].cid=V_GREEN; box[3].s[0] = 0.3; box[3].s[1] = 0.7; box[3].size=1; box[3].cid=V_GREEN; box[0].lcid = V_WHITE; box[1].lcid = V_WHITE; box[2].lcid = V_WHITE; box[3].lcid = V_WHITE; VUnLock(); return((void *)box); } /* end box() */ void *testline (char *name) { VLINE *line; VLock(); line = (VLINE *) VCreateOG (name, V_LINE, 1); line[0].s[0]=0.1; line[0].s[1]=0.2; line[0].s[2]=0.7; line[0].s[3]=0.9; line[0].cid = V_BLUE; VUnLock(); return((void *)line); } /* end bound_box() */ void main() { double H[2][2] = {{12.9, 0},{0, 12.9}}; int i; Bool second = False; VCIRCLE *circle; VLINE *line = (VLINE *)testline("line"); VPOINT *point = (VPOINT *) box("box"); /* default view setup */ VAddDefaultWindow ((volatile double(*)[2])H); watch ("animation", 0); while (watch("animation", 1)<3600.) { if ( (!second) && (watch ("animation", 1)>5)) { VLock(); circle = (VCIRCLE *) colorful ("colorful", 30); VUnLock(); second = True; } if (second) { VLock(); for (i=0; i<30; i++) { circle[i].s[0] += (frandom()-0.5)*0.005; circle[i].s[1] += (frandom()-0.5)*0.005; } VUnLock(); } waitfor(0.01); } printf ("Master process time up.\n"); VCloseWindow(0); VDeleteOG("colorful"); VDeleteOG("box"); } /* end main() */ #endif