#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <string.h> 
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "/usr/include/tcl/tcl.h"
#include "/usr/include/tcl/tk.h"

#include "comdef.H"

double DX, DY, DZ, RX, RY, ax, ay, az, dx, dy, dz; 
unsigned int WMaxX, WMaxY;
int DrwX, DrwY, PrevX, PrevY;
int GoOut=0;	 	 	/* Beware: defaults in TCL, too */
int iax=220, iay=130, iaz=0, piax, piay, piaz, playpressed=4;
int ConfigMode=0, prevmode=3, prevplay=1;
int mass=1, radius=1, ZoomReq=0, IOReq=1;
double DimFact;
int nGPoints=0, i, j, FirstClick=1, SystDrawn=0;
int PX[20], PY[20];
char tempstr[30], mx[30], my[30];

struct TSystem System, CSystem;

struct  TColor {
  unsigned int r, g, b;
} Palette[256];
 
struct GPoint {
  double x, y, z;
  int col;
};

Tk_Window mainWindow;
Tcl_Interp *interp;
static char *display = NULL;

extern Display *disp;
extern GC gc;
extern Window window;
extern int fg, bg;
extern unsigned long pixels[256];
extern GC gc, pmgc;
extern Pixmap pixmap;
extern unsigned long event_mask;

extern InitGraph();
extern ProfDrawSystem_2D();
extern SuckDrawSystem_2D();
extern ArtDrawSystem_2D();
extern ProfDrawSystem_3D();
extern SuckDrawSystem_3D();
extern ArtDrawSystem_3D();

void InitSystem()
{
  FILE *FPalette;

  FPalette=fopen("palette.txt", "r");
  for (i=0; i<256; i++) 
    fscanf(FPalette, "%d %d %d\n", &Palette[i].r, &Palette[i].g, &Palette[i].b);
  fclose(FPalette);

  System.Locked[0]=1;
  System.Mass[0]=100;
  System.Radius[0]=0.3;  
  System.X[0]=1;
  System.Y[0]=1;
  System.Z[0]=1;

  System.Locked[1]=1;
  System.Mass[1]=100;
  System.Radius[1]=0.4;
  System.X[1]=-2;
  System.Y[1]=-3;
  System.Z[1]=-3;

  System.Locked[2]=0;
  System.Mass[2]=1;
  System.Radius[2]=0.05;
  System.X[2]=-3.3;
  System.Y[2]=3.1;
  System.Z[2]=3;
  System.VelX[2]=0.5;
  System.VelY[2]=-0.4;
  System.VelZ[2]=0.5;

  System.nObjects=3; 
  System.nPlanets=1;
  System.G=2E+18;
 
  System.ZXM=System.XMax=10.0;
  System.ZXm=System.XMin=-10.0;
  System.ZYM=System.YMax=10.0;
  System.ZYm=System.YMin=-10.0;
  System.ZZM=System.ZMax=10.0;
  System.ZZm=System.ZMin=-10.0;
  System.MaxAcc=400.0;
  System.dt=0.01;
  System.Col_Amp=1;
  System.track=2, System.mode=3; System.scheme=1; System.space=1;
  System.collision=1; System.zoommode=0;
  memcpy(&CSystem, &System, sizeof(System));
}

Calculate_DimFact()
{
  DimFact=(WMaxX>WMaxY ? WMaxY :WMaxX)/1.9
          /((System.XMax-System.XMin)>(System.YMax-System.YMin) ? 
            ((System.XMax-System.XMin)>(System.ZMax-System.ZMin) ?
             (System.XMax-System.XMin) : (System.ZMax-System.ZMin)) : 
            ((System.YMax-System.YMin)>(System.ZMax-System.ZMin) ?
             (System.YMax-System.YMin) : (System.ZMax-System.ZMin)));
}

int TrX(double px, double py, double pz) 
{
  double tx, ty, tz, x, y, z;

  tx=cos(az)*px+sin(az)*py;
  ty=cos(az)*py-sin(az)*px;
  x=cos(ay)*tx-sin(ay)*pz;
/*  y=ty;
  z=cos(ay)*pz+sin(ay)*tx;
  tx=x;
  ty=cos(ax)*y-sin(ax)*z;
  tz=cos(ax)*z+sin(ax)*y; */

  return (int)floor(DimFact*x+WMaxX/2);
}

int TrY(double px, double py, double pz)
{
  double tx, ty, tz, x, y, z;         

  tx=cos(az)*px+sin(az)*py;
  ty=cos(az)*py-sin(az)*px;
  tz=pz;
  x=cos(ay)*tx-sin(ay)*tz;
  y=ty;
  z=cos(ay)*tz+sin(ay)*tx;
  tx=x;
  ty=cos(ax)*y-sin(ax)*z;
/*  tz=cos(ax)*z+sin(ax)*y;  */

  return (int)floor(DimFact*ty+WMaxY/2);
}

DrawCircle(int x, int y, int rad)
{
  XDrawArc(disp, window, gc, x-rad, y-rad, 2*rad, 2*rad, 0, 100000);
}

ClearWindow()
{
  XSetForeground(disp, gc, bg);
  XFillRectangle(disp, window, gc, 0, 0, WMaxX, WMaxY);
}

int TrX_2D(double x)
{
  if (System.zoommode)
    return (int)floor((x-System.ZXm)/fabs(System.ZXM-System.ZXm)*WMaxX);
  else
    return (int)floor((x-System.XMin)/(System.XMax-System.XMin)*WMaxX);
}

int TrY_2D(double y) 
{  
  if (System.zoommode)
    return WMaxY-(int)floor((y-System.ZYM)/fabs(System.ZYM-System.ZYm)*WMaxY);
  else
    return WMaxY-(int)floor((y-System.YMin)/(System.YMax-System.YMin)*WMaxY);
}

DrawSystemCI(unsigned long axes_col, unsigned long text_col)
{
  int i;
  
  if (System.mode==3) {
    XSetForeground(disp, gc, axes_col);
    XSetLineAttributes(disp, gc, 0, LineSolid, CapButt, JoinMiter);
    XDrawLine(disp, window, gc, PX[7], PY[7], PX[4], PY[4]);
    XDrawLine(disp, window, gc, PX[7], PY[7], PX[2], PY[2]);
    XDrawLine(disp, window, gc, PX[6], PY[6], PX[7], PY[7]);
    XSetLineAttributes(disp, gc, 0, LineOnOffDash, CapButt, JoinMiter);
    XDrawLine(disp, window, gc, PX[0], PY[0], PX[1], PY[1]);
    XDrawLine(disp, window, gc, PX[1], PY[1], PX[2], PY[2]);
    XDrawLine(disp, window, gc, PX[2], PY[2], PX[3], PY[3]);
    XDrawLine(disp, window, gc, PX[3], PY[3], PX[4], PY[4]);
    XDrawLine(disp, window, gc, PX[4], PY[4], PX[5], PY[5]);
    XDrawLine(disp, window, gc, PX[5], PY[5], PX[6], PY[6]);
    XDrawLine(disp, window, gc, PX[0], PY[0], PX[5], PY[5]);
    XDrawLine(disp, window, gc, PX[1], PY[1], PX[6], PY[6]);
    XDrawLine(disp, window, gc, PX[0], PY[0], PX[3], PY[3]);
    XSetLineAttributes(disp, gc, 0, LineSolid, CapButt, JoinMiter);
    XDrawLine(disp, window, gc, PX[4], PY[4], PX[8], PY[8]);
    XDrawLine(disp, window, gc, PX[4], PY[4], PX[9], PY[9]);
    XDrawLine(disp, window, gc, PX[2], PY[2], PX[11], PY[11]);
    XDrawLine(disp, window, gc, PX[2], PY[2], PX[12], PY[12]);
    XDrawLine(disp, window, gc, PX[6], PY[6], PX[14], PY[14]);
    XDrawLine(disp, window, gc, PX[6], PY[6], PX[15], PY[15]);
    XSetForeground(disp, gc, text_col);
    XDrawString(disp, window, gc, PX[10], PY[10], "X", 1);
    XDrawString(disp, window, gc, PX[13], PY[13], "Y", 1);
    XDrawString(disp, window, gc, PX[16], PY[16], "Z", 1);
  }

  for (i=0; i<System.nObjects; i++)  {
    if (System.Locked[i]) XSetForeground(disp, gc, text_col);
    else XSetForeground(disp, gc, axes_col);
    if (System.mode==3) 
      DrawCircle(TrX(System.X[i], System.Y[i], System.Z[i]), 
        TrY(System.X[i], System.Y[i], System.Z[i]), 
        (int)floor(WMaxX>WMaxY ?
        System.Radius[i]/(System.YMax-System.YMin)*WMaxY : 
        System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
    else
      DrawCircle(TrX_2D(System.X[i]), TrY_2D(System.Y[i]), 
        (int)floor(WMaxX>WMaxY ?
         System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
         System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
  }
}

ComputeCubeCoords()
{
  PX[0]=TrX(System.XMax, System.YMax, System.ZMax);
  PY[0]=TrY(System.XMax, System.YMax, System.ZMax);
  PX[1]=TrX(System.XMin, System.YMax, System.ZMax);
  PY[1]=TrY(System.XMin, System.YMax, System.ZMax);
  PX[2]=TrX(System.XMin, System.YMax, System.ZMin);
  PY[2]=TrY(System.XMin, System.YMax, System.ZMin);
  PX[3]=TrX(System.XMax, System.YMax, System.ZMin);
  PY[3]=TrY(System.XMax, System.YMax, System.ZMin);
  PX[4]=TrX(System.XMax, System.YMin, System.ZMin);
  PY[4]=TrY(System.XMax, System.YMin, System.ZMin);
  PX[5]=TrX(System.XMax, System.YMin, System.ZMax);
  PY[5]=TrY(System.XMax, System.YMin, System.ZMax);
  PX[6]=TrX(System.XMin, System.YMin, System.ZMax);
  PY[6]=TrY(System.XMin, System.YMin, System.ZMax);
  PX[7]=TrX(System.XMin, System.YMin, System.ZMin);
  PY[7]=TrY(System.XMin, System.YMin, System.ZMin);
  PX[8]=TrX(System.XMax-(System.XMax-System.XMin)*0.04, 
            System.YMin+(System.YMax-System.YMin)*0.015, System.ZMin);
  PY[8]=TrY(System.XMax-(System.XMax-System.XMin)*0.04, 
            System.YMin+(System.YMax-System.YMin)*0.015, System.ZMin);
  PX[9]=TrX(System.XMax-(System.XMax-System.XMin)*0.04, 
            System.YMin-(System.YMax-System.YMin)*0.015, System.ZMin);
  PY[9]=TrY(System.XMax-(System.XMax-System.XMin)*0.04, 
            System.YMin-(System.YMax-System.YMin)*0.015, System.ZMin);
  PX[10]=TrX(System.XMax, System.YMin+(System.XMax-System.XMin)*0.04, 
             System.ZMin);
  PY[10]=TrY(System.XMax, System.YMin+(System.XMax-System.XMin)*0.04, 
             System.ZMin);
  PX[11]=TrX(System.XMin+(System.XMax-System.XMin)*0.015, 
             System.YMax-(System.YMax-System.YMin)*0.04, System.ZMin);
  PY[11]=TrY(System.XMin+(System.XMax-System.XMin)*0.015, 
             System.YMax-(System.YMax-System.YMin)*0.04, System.ZMin);
  PX[12]=TrX(System.XMin-(System.XMax-System.XMin)*0.015, 
             System.YMax-(System.YMax-System.YMin)*0.04, System.ZMin);
  PY[12]=TrY(System.XMin-(System.XMax-System.XMin)*0.015, 
             System.YMax-(System.YMax-System.YMin)*0.04, System.ZMin);
  PX[13]=TrX(System.XMin+(System.XMax-System.XMin)*0.04, System.YMax, 
             System.ZMin);
  PY[13]=TrY(System.XMin+(System.XMax-System.XMin)*0.04, System.YMax, 
             System.ZMin);
  PX[14]=TrX(System.XMin+(System.XMax-System.XMin)*0.015, System.YMin, 
             System.ZMax-(System.ZMax-System.ZMin)*0.04);
  PY[14]=TrY(System.XMin+(System.XMax-System.XMin)*0.015, System.YMin, 
	     System.ZMax-(System.ZMax-System.ZMin)*0.04);
  PX[15]=TrX(System.XMin-(System.XMax-System.XMin)*0.015, System.YMin, 
             System.ZMax-(System.ZMax-System.ZMin)*0.04);
  PY[15]=TrY(System.XMin-(System.XMax-System.XMin)*0.015, System.YMin, 
             System.ZMax-(System.ZMax-System.ZMin)*0.04);
  PX[16]=TrX(System.XMin+(System.XMax-System.XMin)*0.04, System.YMin, 
             System.ZMax);
  PY[16]=TrY(System.XMin+(System.XMax-System.XMin)*0.04, System.YMin, 
             System.ZMax); 
}

ComputeXEvents() 
{
  XEvent report;

  XCheckWindowEvent(disp, window, event_mask, &report);
  switch (report.type) {
    case Expose: break;
    case ConfigureNotify:
      if ((report.xconfigure.width>50)&&(report.xconfigure.height>50)
         &&((WMaxX!=report.xconfigure.width)||(WMaxY!=report.xconfigure.height))) {
        WMaxX=report.xconfigure.width;
        WMaxY=report.xconfigure.height;
        DimFact=(WMaxX>WMaxY ? WMaxY :WMaxX)/(System.XMax-System.XMin)/1.9;
        ClearWindow();
      }
      break;
    case ButtonPress: 
      if (ConfigMode) {
        if (System.mode==2) {
          System.X[System.nObjects]=(report.xmotion.x/(float)WMaxX)*
                                            (System.XMax-System.XMin)
                                            +System.XMin;
          System.Y[System.nObjects]=System.YMax-
                                            (report.xmotion.y/(float)WMaxY)* 
                                            (System.YMax-System.YMin);
          System.Radius[System.nObjects]=
            ((System.XMax-System.XMin)>(System.YMax-System.YMin) ? 
              (System.YMax-System.YMin) : (System.XMax-System.XMin))
            *radius/(float)1000;

          XSetForeground(disp, gc, (report.xbutton.button!=3 ? 
                                    pixels[2] : fg));
          DrawCircle(report.xmotion.x, report.xmotion.y, 
            (int)floor(WMaxX>WMaxY ? 
             System.Radius[System.nObjects]/(System.YMax-System.YMin) 
             *WMaxY : 
             System.Radius[System.nObjects]/(System.XMax-System.XMin)  
             *WMaxX));
        } else { 
        }
        System.Mass[System.nObjects]=mass;
        System.VelX[System.nObjects]=0;
        System.VelY[System.nObjects]=0;
	System.VelZ[System.nObjects]=0;
        if (report.xbutton.button==1) {
          System.Locked[System.nObjects]=0;
          System.nObjects++;
        } else 
          if (report.xbutton.button==2) {
            System.Locked[System.nObjects]=1;
            System.nObjects++;
          } else {
            System.Locked[System.nObjects]=0;
            System.nObjects++;
            System.nPlanets++;
          }
      } else
        if ((ZoomReq)&&(!System.zoommode)) {
          if (System.mode==2) {
            if (FirstClick) {
 	      System.ZXM=System.ZXm=(report.xmotion.x/(float)WMaxX)*
                         (System.XMax-System.XMin)+System.XMin;
              System.ZYM=System.ZYm=System.YMax-(report.xmotion.y/(float)WMaxY)*
                         (System.YMax-System.YMin);
              XSetForeground(disp, gc, bg);
              XSetFunction(disp, gc, GXxor);
              XDrawRectangle(disp, window, gc,
                             TrX_2D(System.ZXm), TrY_2D(System.ZYm),
                             TrX_2D(System.XMin+fabs(System.ZXm-System.ZXM)), 
			     TrY_2D(System.YMax-fabs(System.ZYm-System.ZYM)));
              XSetFunction(disp, gc, GXcopy);
	      FirstClick=0;
	    } else {
              FirstClick=1;
              System.zoommode=1;
              ZoomReq=0;
              SystDrawn=0;
              ClearWindow();
            }
          } else {
          }
        } 
      break;
    case MotionNotify:
      if (ConfigMode) {
        if (System.mode==2) {
          XSetForeground(disp, gc, bg);
          XDrawString(disp, window, gc, 10, 16, mx, strlen(mx));
          XDrawString(disp, window, gc, 10, 30, my, strlen(my));
          XSetForeground(disp, gc, fg); 
          sprintf(mx, "x = %f  ", 
                  report.xmotion.x/(float)WMaxX*
                  (System.XMax-System.XMin)+System.XMin);
          sprintf(my, "y = %f  ", 
                  System.YMax-report.xmotion.y/(float)WMaxY*
                  (System.YMax-System.YMin));
          XDrawString(disp, window, gc, 10, 16, mx, strlen(mx));
          XDrawString(disp, window, gc, 10, 30, my, strlen(my));
        } else {
        }
      } else
        if ((ZoomReq)&&(!FirstClick)&&(!System.zoommode)) { 
          XSetForeground(disp, gc, bg);
          XSetFunction(disp, gc, GXxor);
          XDrawRectangle(disp, window, gc, 
                         TrX_2D(System.ZXm), TrY_2D(System.ZYm), 
                         TrX_2D(System.XMin+fabs(System.ZXm-System.ZXM)),
	                 TrY_2D(System.YMax-fabs(System.ZYm-System.ZYM)));
          System.ZXM=(report.xmotion.x/(float)WMaxX)*
                     (System.XMax-System.XMin)+System.XMin;
          System.ZYM=System.YMax-(report.xmotion.y/(float)WMaxY)*
                     (System.YMax-System.YMin);
          XDrawRectangle(disp, window, gc, 
                         TrX_2D(System.ZXm), TrY_2D(System.ZYm),
                         TrX_2D(System.XMin+fabs(System.ZXm-System.ZXM)),
                         TrY_2D(System.YMax-fabs(System.ZYm-System.ZYM)));
          XSetFunction(disp, gc, GXcopy);
        }
      break;

  }
  report.type=0;
}

Set_TCL_ObjsVar()
{
  int i;
  char temp2[150];

  for (i=0; i<System.nObjects; i++) {
    gcvt(i+1, 2, tempstr);
    gcvt(System.Mass[i], 15, temp2);
    Tcl_SetVar2(interp, "vmass", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.Radius[i], 15, temp2);
    Tcl_SetVar2(interp, "vradius", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.X[i], 15, temp2);
    Tcl_SetVar2(interp, "px", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.Y[i], 15, temp2);
    Tcl_SetVar2(interp, "py", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.Z[i], 15, temp2);
    Tcl_SetVar2(interp, "pz", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.VelX[i], 15, temp2);
    Tcl_SetVar2(interp, "vx", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.VelY[i], 15, temp2);
    Tcl_SetVar2(interp, "vy", tempstr, temp2, TCL_GLOBAL_ONLY);
    gcvt(System.VelZ[i], 15, temp2);
    Tcl_SetVar2(interp, "vz", tempstr, temp2, TCL_GLOBAL_ONLY);
    sprintf(temp2, "%d", System.Locked[i]);
    Tcl_SetVar2(interp, "locked", tempstr, temp2, TCL_GLOBAL_ONLY);
  }
}

Get_TCL_ObjsVar()
{
  int i;
  
  Tcl_GetInt(interp, "nobjs", &System.nObjects);
  
/*  printf("%d\n", System.nObjects); */
  
  for (i=0; i<System.nObjects; i++) {
    gcvt(i+1, 2, tempstr);
    System.Mass[i]=atof(Tcl_GetVar2(interp, "vmass", tempstr, TCL_GLOBAL_ONLY));
    System.Radius[i]=atof(Tcl_GetVar2(interp, "vradius", tempstr, 
                                      TCL_GLOBAL_ONLY));
    System.X[i]=atof(Tcl_GetVar2(interp, "px", tempstr, TCL_GLOBAL_ONLY));
    System.Y[i]=atof(Tcl_GetVar2(interp, "py", tempstr, TCL_GLOBAL_ONLY));
    System.Z[i]=atof(Tcl_GetVar2(interp, "pz", tempstr, TCL_GLOBAL_ONLY));
    System.VelX[i]=atof(Tcl_GetVar2(interp, "vx", tempstr, TCL_GLOBAL_ONLY));
    System.VelY[i]=atof(Tcl_GetVar2(interp, "vy", tempstr, TCL_GLOBAL_ONLY));
    System.VelZ[i]=atof(Tcl_GetVar2(interp, "vz", tempstr, TCL_GLOBAL_ONLY));
    System.Locked[i]=atoi(Tcl_GetVar2(interp, "locked", tempstr, TCL_GLOBAL_ONLY));
/*    printf("%f, %f, %f\n", System.X[i], System.Y[i], System.Z[i]);  */
  }
  memcpy(&CSystem, &System, sizeof(System));
}

Start_TCL(char * BinName)
{
  interp = Tcl_CreateInterp();
  mainWindow = Tk_CreateMainWindow(interp, display, BinName, "Tk");
  if (mainWindow == NULL) {
    fprintf(stderr, "%s\n", interp->result);
    exit(1);
  }
  if (Tcl_Init(interp) == TCL_ERROR) 
    fprintf(stderr, "Tcl_Init failed: %s\n", interp->result);
  if (Tk_Init(interp) == TCL_ERROR) 
    fprintf(stderr, "Tk_Init failed: %s\n", interp->result);
  Tcl_EvalFile(interp, "god.tcl");
  Tcl_LinkVar(interp, "GoOut", (char *)&GoOut, TCL_LINK_INT);
  Tcl_LinkVar(interp, "xangle", (char *) &iax, TCL_LINK_INT);
  gcvt(iax, 3, tempstr);
  Tcl_SetVar(interp, "xangle", tempstr, 0);
  Tcl_LinkVar(interp, "yangle", (char *) &iay, TCL_LINK_INT);
  gcvt(iay, 3, tempstr);
  Tcl_SetVar(interp, "yangle", tempstr, 0);
  Tcl_LinkVar(interp, "zangle", (char *) &iaz, TCL_LINK_INT);
  gcvt(iaz, 3, tempstr);
  Tcl_SetVar(interp, "zangle", tempstr, 0);
  Tcl_LinkVar(interp, "kG", (char *) &System.G, TCL_LINK_DOUBLE);
  gcvt(System.G, 10, tempstr);
  Tcl_SetVar(interp, "kG", tempstr, 0);
  Tcl_LinkVar(interp, "dt", (char *) &System.dt, TCL_LINK_DOUBLE);
  gcvt(System.dt, 10, tempstr);
  Tcl_SetVar(interp, "dt", tempstr, 0);
  Tcl_LinkVar(interp, "maxacc", (char *) &System.MaxAcc, TCL_LINK_DOUBLE);
  gcvt(System.MaxAcc, 10, tempstr);
  Tcl_SetVar(interp, "maxacc", tempstr, 0);
  Tcl_LinkVar(interp, "col_amp",(char *) &System.Col_Amp, TCL_LINK_DOUBLE);
  gcvt(System.Col_Amp, 10, tempstr);
  Tcl_SetVar(interp, "col_amp", tempstr, 0);
  Tcl_LinkVar(interp, "xmin",(char *) &System.XMin, TCL_LINK_DOUBLE);
  gcvt(System.XMin, 10, tempstr);
  Tcl_SetVar(interp, "xmin", tempstr, 0);
  Tcl_LinkVar(interp, "xmax",(char *) &System.XMax, TCL_LINK_DOUBLE);
  gcvt(System.XMax, 10, tempstr);
  Tcl_SetVar(interp, "xmax", tempstr, 0);
  Tcl_LinkVar(interp, "ymin",(char *) &System.YMin, TCL_LINK_DOUBLE);
  gcvt(System.YMin, 10, tempstr);
  Tcl_SetVar(interp, "ymin", tempstr, 0);
  Tcl_LinkVar(interp, "ymax",(char *) &System.YMax, TCL_LINK_DOUBLE);
  gcvt(System.YMax, 10, tempstr);
  Tcl_SetVar(interp, "ymax", tempstr, 0);
  Tcl_LinkVar(interp, "zmin",(char *) &System.ZMin, TCL_LINK_DOUBLE);
  gcvt(System.ZMin, 10, tempstr);
  Tcl_SetVar(interp, "zmin", tempstr, 0);
  Tcl_LinkVar(interp, "zmax",(char *) &System.ZMax, TCL_LINK_DOUBLE);
  gcvt(System.ZMax, 10, tempstr);
  Tcl_SetVar(interp, "zmax", tempstr, 0);
  Tcl_LinkVar(interp, "IOreq", (char *)&IOReq, TCL_LINK_INT); 
  Tcl_LinkVar(interp, "playpressed", (char *)&playpressed, TCL_LINK_INT);
  Tcl_LinkVar(interp, "nobjs", (char *)&System.nObjects, TCL_LINK_INT);
  Tcl_LinkVar(interp, "track", (char *)&System.track, TCL_LINK_INT);
  Tcl_LinkVar(interp, "mode", (char *)&System.mode, TCL_LINK_INT);
  Tcl_LinkVar(interp, "scheme", (char *)&System.scheme, TCL_LINK_INT);
  Tcl_LinkVar(interp, "configmode", (char *)&ConfigMode, TCL_LINK_INT);
  Tcl_LinkVar(interp, "mass", (char *)&mass, TCL_LINK_INT);
  Tcl_LinkVar(interp, "radius", (char *)&radius, TCL_LINK_INT);
  Tcl_LinkVar(interp, "space", (char *)&System.space, TCL_LINK_INT);
  Tcl_LinkVar(interp, "collision", (char *)&System.collision, TCL_LINK_INT);
  Tcl_LinkVar(interp, "zoom", (char *)&System.zoommode, TCL_LINK_INT);
  Tcl_LinkVar(interp, "zoommode", (char *)&ZoomReq, TCL_LINK_INT);
}

main(int argc, char **argv)
{
  InitSystem();
  Start_TCL(argv[0]);
  printf("Initialized TCL/TK...\n");
  InitGraph();
  WMaxX=MAXX; 
  WMaxY=MAXY; 
  Calculate_DimFact();
  printf("Initialized graphics...\n");
/*  Get_TCL_ObjsVar();  */
  while (!GoOut) {
    ComputeXEvents();
    piax=iax; piay=iay; piaz=iaz;
    Tk_DoOneEvent(TK_DONT_WAIT);                       
              
    if (IOReq==1) {
      Get_TCL_ObjsVar();
      IOReq=0;
      ClearWindow();
      SystDrawn=0;
    } 

    if (prevmode!=System.mode) {
      ClearWindow();
      prevmode=System.mode;
      SystDrawn=0;
    }

    if ((ZoomReq)&&(System.zoommode)) {
      ZoomReq=0;
      System.zoommode=0;
    }     
    if ((playpressed!=1)&&((!SystDrawn)||(piax!=iax)||(piay!=iay)||(piaz!=iaz))) { 
      DrawSystemCI(bg, bg);
      Calculate_DimFact();
      ax=iax/180.0*PI;                                         
      ay=iay/180.0*PI;      
      az=iaz/180.0*PI;
      ComputeCubeCoords();
      DrawSystemCI(fg, pixels[2]);
      SystDrawn=1;
    }
    XFlush(disp);
    if (playpressed==1) {
      ClearWindow();
      prevplay=1;
      SystDrawn=0;
    } else 
      if (playpressed==2) {
        if (prevplay==1) {
          DrawSystemCI(bg, bg);
          prevplay=2;
        }
        System.nObjects=CSystem.nObjects; 
    	System.nPlanets=CSystem.nPlanets;
        memcpy(&System.X, &CSystem.X, CSystem.nObjects*sizeof(System.X[0]));
	memcpy(&System.Y, &CSystem.Y, CSystem.nObjects*sizeof(System.Y[0]));
        memcpy(&System.Z, &CSystem.Z, CSystem.nObjects*sizeof(System.Z[0]));
        memcpy(&System.VelX, &CSystem.VelX,
	       CSystem.nObjects*sizeof(System.VelX[0]));
        memcpy(&System.VelY, &CSystem.VelY,
               CSystem.nObjects*sizeof(System.VelY[0]));
        memcpy(&System.VelZ, &CSystem.VelZ,
               CSystem.nObjects*sizeof(System.VelZ[0]));
        memcpy(&System.Locked, &CSystem.Locked,
               CSystem.nObjects*sizeof(System.Locked[0]));
      }
    while ((playpressed==1)&&(!GoOut)&&(!ConfigMode)) {
      ComputeXEvents();

      if (prevmode!=System.mode) {
        ClearWindow();
        prevmode=System.mode;
        SystDrawn=0;
      }

      piax=iax; piay=iay; piaz=iaz;
      Tk_DoOneEvent(TK_DONT_WAIT);
      
      if (IOReq==1) {
        Get_TCL_ObjsVar();
        IOReq=0;
        ClearWindow();
        SystDrawn=0;
      } 
      
      if ((System.mode==3)&&((piax!=iax)||(piay!=iay)||(piaz!=iaz))) {
        Calculate_DimFact();
        ax=iax/180.0*PI;
        ay=iay/180.0*PI;
        az=iaz/180.0*PI;
      }

      if (System.mode==2) 
        switch (System.scheme) {
          case 1: ProfDrawSystem_2D();
             break;
          case 2: SuckDrawSystem_2D();
             break;
          case 3: ArtDrawSystem_2D();
             break;
        }
      else 
        switch (System.scheme) {
          case 1: ProfDrawSystem_3D();
             break;
          case 2: SuckDrawSystem_3D();
             break;
          case 3: ArtDrawSystem_3D();
             break;
        }
    } 
    if (ConfigMode) {
      ClearWindow();
      System.nObjects=0;
      System.nPlanets=0;
    }
    while ((ConfigMode)&&(!GoOut)) {
      ComputeXEvents();
      Tk_DoOneEvent(TK_DONT_WAIT);
      if (!ConfigMode) {
        memcpy(&CSystem, &System, sizeof(System));     
        Set_TCL_ObjsVar();
        ClearWindow(); SystDrawn=0;
      } 
    }
  }
  Tcl_DeleteInterp(interp);
  XFreeGC (disp, gc);
  XFreePixmap (disp, pixmap);
  XDestroyWindow (disp, window);
  XCloseDisplay (disp);
  printf("See you in a wuanna!\n");
  exit(0);  
}

