home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff280.lzh
/
CM
/
cm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-20
|
29KB
|
1,405 lines
/*
* Celestial Mechanics Simulation Tool
*
* W. John Guineau
* 3 Royal Crest Drive #9
* Marlboro, Mass. 01752
* (508) 485-6233
*
* Files:
* cm.c
* cm.h
* cm.doc
*
* To Compile with Lattice 5.02:
*
* lc -b0 -Lm cm
*
*
* NOTICE
* ------
*
* I have placed this software in the Public Domain with the
* condition that all the files remain together and that I remain
* listed as the original author. This software may not be used for
* commercial purposes or to make money in any way without expressed
* written permission from the author (me). I'm including the source
* code so if you make any significant modifications please concider
* sending me a copy at the above address. I'd also be interested in
* any interesting saved setup files you create.
*
*
* This is my first Amiga program so I welcome any comments at all.
* I wrote this program as both a way to learn the Amiga environment
* and in response to a conversation I had with a friend on Celestial
* Mechanics.
*
*
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/display.h>
#include <graphics/text.h>
#include "cm.h"
#define NOWAIT 0
#define WAIT 1
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
struct IntuiMessage *message;
struct Screen *s;
struct Window *w;
struct Window *pw;
struct RastPort *rp;
struct RastPort *prp;
struct ViewPort *vp;
#define ReqNone 0
#define ReqBody 1
#define ReqSetup 2
#define ReqFile 3
#define ReqAbout 4
UBYTE CancelHit=0; /* If user selects CANCEL from Reqester */
UBYTE ReqActive=ReqNone; /* Set when a Reqester is active */
/* to keep DoIntuiEvents() from returning */
/* until it gets a REQCLEAR msg */
struct setup {
double G;
double ds;
double dt;
UBYTE t;
WORD TrailLength;
UBYTE ShowTime;
} SI;
#define MAXTRAILEN 300
struct Body { /* Info for a Celestial Body */
UBYTE real; /* If it's real */
UBYTE fixed; /* Body fixed in place */
UBYTE pen; /* Color Register */
char name[10]; /* user given name */
ULONG Radius; /* radius */
double Mass; /* mass */
double x,y; /* current position */
double Vx,Vy; /* velocity components */
double Fx,Fy; /* resultant force components */
double Dir; /* direction angle (radians) */
double TrailX[MAXTRAILEN]; /* X of trail of pixels to clear */
double TrailY[MAXTRAILEN]; /* X of trail of pixels to clear */
WORD TrailIDX;
};
#define MAXBODYS 10
struct Body Bodys[MAXBODYS]; /* The array of bodys */
BYTE CurBody,TotalBodys=0;
ULONG Et; /* elapsed time */
#define MODE_CREATE 1
#define MODE_MODIFY 2
#define MODE_START 3
#define MODE_STOP 4
UBYTE mode = MODE_STOP; /* Current simulation mode */
/* pointer text for ShowMouse() */
char pbuf[80];
struct IntuiText pos_txt = {
WHTPEN,BLKPEN, /* FrontPen, BackPen */
JAM2, /* DrawMode */
7,2, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* TextAttr */
pbuf, /* IText */
NULL /* NextText */
};
struct MsgPort *TimerPort; /* for Timer stuff */
struct timerequest *TR;
UBYTE TimerOpen=0;
/* ============================================================
* Main
*
* ============================================================*/
main(argc,argv)
int argc;
char *argv[];
{
OpenStuff();
Init();
DoIntuiEvents(WAIT);
return(0);
}
OpenStuff()
{
TimerPort = (struct MsgPort *)CreatePort(0,0);
if(TimerPort == 0) {
printf("Cant get a Timer Port\n");
CleanUp();
exit(10);
};
TR = (struct timerequest *)CreateExtIO(TimerPort,
sizeof(struct timerequest));
if(TR == 0) {
printf("Cant get a Timer Request\n");
CleanUp();
exit(11);
};
if(OpenDevice(TIMERNAME,UNIT_VBLANK,TR,0) != 0) {
printf("Cant open Timer Device\n");
CleanUp();
exit(12);
};
TimerOpen = 1;
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) {
printf("no graphics library!!!\n");
CleanUp();
exit(13);
};
if(!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",0))) {
printf("no intuition here!!\n");
CleanUp();
exit(14);
};
if (!(s = (struct Screen *)OpenScreen(&ns) )) {
printf("could not open the screen\n");
CleanUp();
exit(15);
};
/*
* set up color map for new screen
*/
vp = (struct ViewPort *)&s->ViewPort;
LoadRGB4(vp,colortable,COLORS);
nw.Screen = s; /* point to our screen */
npw.Screen = s; /* pointer window struct also */
if (!(w = (struct Window *)OpenWindow(&nw) )) {
printf("could not open the window\n");
CleanUp();
exit(16);
};
rp = w->RPort;
SetAPen(rp,WHTPEN);
SetMenuStrip(w,&Control);
return(0);
}
Init()
{
SI.G = 6.67;
SI.ds = 1.0;
SI.dt = 1.0;
SI.t = 0;
SI.TrailLength = 0;
cancel_text.IText = cantxt;
OffMenu(w,MN_CStop);
OffMenu(w,MN_EMod);
OffMenu(w,MN_FSScr);
ClearScreen();
ClearBodys();
SetupGADefaults();
BodyGADefaults();
return(0);
}
ClearScreen()
{
SetRast(rp,0);
SetAPen(rp,WHTPEN);
return(0);
}
DoIntuiEvents(wait)
UBYTE wait;
{
ULONG MessageClass;
USHORT code,qual;
struct Gadget *GAD;
struct MsgPort *mp;
mp = w->UserPort;
for(;;) {
if(message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
MessageClass = message->Class;
code = message->Code;
qual = message->Qualifier;
GAD = (struct Gadget *)message->IAddress;
ReplyMsg(message);
switch (MessageClass) {
case GADGETUP : DoGadget(GAD);
break;
case MENUPICK : if(code != MENUNULL) {
DoMenu(code);
};
break;
case CLOSEWINDOW : CleanUp();
exit(0);
break;
case MOUSEBUTTONS: if(code == SELECTDOWN) {
MakeBody(w->GZZMouseX,w->GZZMouseY);
};
break;
case MOUSEMOVE : if(mode == MODE_CREATE) {
ShowMouse(w->GZZMouseX,w->GZZMouseY);
};
break;
case REQCLEAR :
ReqActive = ReqNone;
break;
default :
break;
};
} else {
if(!wait&&!ReqActive) return(0);
WaitPort(mp);
};
};
return(0);
}
DoGadget(GAD)
struct Gadget *GAD;
{
ULONG val;
struct StringInfo *info;
info = (struct StringInfo *)GAD->SpecialInfo;
val = info->LongInt;
switch(GAD->GadgetID) {
case NAMEGAD :
ActivateGadget(&mass,w,&BodyInfo);
break;
case RADIUSGAD :
break;
case MASSGAD :
ActivateGadget(&velocity,w,&BodyInfo);
break;
case VELOCITYGAD :
ActivateGadget(&direction,w,&BodyInfo);
break;
case DIRECTIONGAD :
break;
case OKGAD :
CancelHit=0;
if(pw)
WindowToFront(pw);
break;
case CANCELGAD :
CancelHit=1;
if(pw)
WindowToFront(pw);
break;
case RESETGAD :
switch(ReqActive) {
case ReqBody : BodyGADefaults();
RefreshGadgets(&mass,
w,&BodyInfo);
break;
case ReqSetup : SetupGADefaults();
RefreshGadgets(&dt,
w,&SetupInfo);
break;
};
break;
case GGAD :
ActivateGadget(&dt,w,&SetupInfo);
break;
case DTGAD :
ActivateGadget(&t,w,&SetupInfo);
break;
case TGAD :
ActivateGadget(&ds,w,&SetupInfo);
break;
case DSGAD :
ActivateGadget(&tl,w,&SetupInfo);
break;
case TLGAD :
break;
case COLOR1GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR2GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR3GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR4GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR5GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR6GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case COLOR7GAD :
Bodys[CurBody].pen = (UBYTE)GAD->UserData;
break;
case FNOKGAD :
CancelHit=0;
break;
case FNCANGAD :
CancelHit=1;
break;
case STGAD : if(st.Flags&SELECTED) {
st.GadgetText = &yes_text;
RefreshGadgets(&st,w,&SetupInfo);
SI.ShowTime=1;
} else {
st.GadgetText = &no_text;
RefreshGadgets(&st,w,&SetupInfo);
SI.ShowTime=0;
};
break;
case FXGAD : if(fixed.Flags&SELECTED) {
fixed.GadgetText = &yes_text;
RefreshGadgets(&fixed,w,&BodyInfo);
Bodys[CurBody].fixed=1;
} else {
fixed.GadgetText = &no_text;
RefreshGadgets(&fixed,w,&BodyInfo);
Bodys[CurBody].fixed=0;
};
break;
default :
break;
};
return(0);
}
DoMenu(MN)
USHORT MN;
{
switch(MENUNUM(MN)) {
case M_Control :
switch(ITEMNUM(MN)) {
case I_Stop :
mode = MODE_STOP;
ClosePw();
OffMenu(w,MN_CStop);
OnMenu(w,MN_ECreate);
OnMenu(w,MN_ESetup);
OnMenu(w,MN_EMod);
OnMenu(w,MN_EClearS);
OnMenu(w,MN_EClearB);
OnMenu(w,MN_FSDat);
OnMenu(w,MN_FLDat);
OnMenu(w,MN_CStart);
break;
case I_Start :
if(TotalBodys == 0) {
MSG("No Bodys Created!!","OK","OK");
break;
};
mode = MODE_START;
ModifyIDCMP(w,IDCMPFL);
if(SI.ShowTime) OpenPw();
OffMenu(w,MN_ECreate);
OffMenu(w,MN_ESetup);
OffMenu(w,MN_EMod);
OffMenu(w,MN_CStart);
OffMenu(w,MN_EClearS);
OffMenu(w,MN_EClearB);
OffMenu(w,MN_FSDat);
OffMenu(w,MN_FLDat);
OnMenu(w,MN_CStop);
DoSimulation();
break;
};
break;
case M_Edit :
switch(ITEMNUM(MN)) {
case I_ClearB : if(MSG("Really Clear Bodys?",
"YES!","NO!!")) {
ClearBodys();
OnMenu(w,MN_FSDat);
OnMenu(w,MN_FLDat);
};
break;
case I_ClearS :
ClearScreen();
break;
case I_Modify :
mode = MODE_MODIFY;
ModifyBodys();
break;
case I_Create :
mode = MODE_CREATE;
ModifyIDCMP(w,IDCMPFL_MM);
OpenPw();
OnMenu(w,MN_CStart);
OnMenu(w,MN_EMod);
OffMenu(w,MN_ECreate);
OffMenu(w,MN_FLDat);
cancel_text.IText = cantxt;
break;
case I_Setup :
Request(&SetupInfo,w);
Sleep(0L,100000L);
ActivateGadget(&G,w,&SetupInfo);
ReqActive = ReqSetup;
DoIntuiEvents(NOWAIT);
cancel_text.IText = cantxt;
if(!CancelHit) GetSetupInfo();
break;
};
break;
case M_File :
switch(ITEMNUM(MN)) {
case I_Exit :
CleanUp();
exit(0);
break;
case I_SavScr :
break;
case I_SavDat :
DoSaveData();
break;
case I_LoadDat :
DoLoadData();
break;
case I_About :
Request(&RAbout,w);
ReqActive = ReqAbout;
DoIntuiEvents(NOWAIT);
break;
};
break;
};
return(0);
}
ShowMouse(x,y)
SHORT x,y;
{
if(x<0||y<0) return(0);
sprintf(pbuf," %.3e , %.3e",
(double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
PrintIText(prp,&pos_txt,0,0);
return(0);
}
OpenPw()
{
if(pw) return(0);
if (!(pw = (struct Window *)OpenWindow(&npw) )) {
printf("could not open the pointer window\n");
CleanUp();
exit(17);
};
prp = pw->RPort;
SetAPen(prp,BLKPEN);
SetBPen(prp,WHTPEN);
return(0);
}
ClosePw()
{
if(pw) CloseWindow(pw);
pw = (struct Window *)NULL;
return(0);
}
GetBodyInfo()
{
double V;
strcpy(Bodys[CurBody].name,name_sbuf);
if(sscanf(mass_sbuf,"%le",&Bodys[CurBody].Mass) != 1) {
MSG("Bad Value for Mass!","OK","OK");
return(0);
};
Bodys[CurBody].Dir =
(double)direction_txstr.LongInt * PI/180.0;
if(sscanf(velocity_sbuf,"%le",&V) != 1) {
MSG("Bad Value for Velocity!","OK","OK");
return(0);
};
Bodys[CurBody].Vx =
V * cos(Bodys[CurBody].Dir);
Bodys[CurBody].Vy =
V * sin(Bodys[CurBody].Dir);
if(Bodys[CurBody].pen == 0)
Bodys[CurBody].pen = WHTPEN;
Bodys[CurBody].Fx = 0.0;
Bodys[CurBody].Fy = 0.0;
return(0);
}
GetSetupInfo()
{
WORD n;
if(sscanf(G_sbuf,"%le",&SI.G) != 1) {
MSG("Bad Value for G!","OK","OK");
return(0);
};
if(sscanf(ds_sbuf,"%le",&SI.ds) != 1) {
MSG("Bad Value for ds!","OK","OK");
return(0);
};
if(sscanf(dt_sbuf,"%le",&SI.dt) != 1) {
MSG("Bad Value for dt!","OK","OK");
return(0);
};
SI.t = (UBYTE)t_txstr.LongInt;
n = (WORD)tl_txstr.LongInt;
if(n>MAXTRAILEN) {
MSG("TrailLength too large!","OK","OK");
return(0);
};
SI.TrailLength=n;
return(0);
}
MakeBody(x,y)
SHORT x,y;
{
if(mode != MODE_CREATE)
return(0);
if(x<0 || y<0)
return(0);
if(TotalBodys++ > MAXBODYS) {
TotalBodys--;
MSG("No More Body's Available!!","OK","OK");
return(0);
};
SetAPen(rp,REDPEN);
WritePixel(rp,x,y);
CurBody = FindFreeBody();
if(CurBody == -1) {
TotalBodys--;
MSG("No More Body's Available!!","OK","OK");
return(0);
};
cancel_text.IText = cantxt;
BodyGADefaults();
sprintf(xy_buf," %.3e , %.3e ",
(double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
Request(&BodyInfo,w);
ReqActive = ReqBody;
Sleep(0L,100000L);
ActivateGadget(&name,w,&BodyInfo);
DoIntuiEvents(NOWAIT);
if(CancelHit) {
TotalBodys--;
SetAPen(rp,BLKPEN);
WritePixel(rp,x,y);
return(0);
};
GetBodyInfo();
if(Bodys[CurBody].Mass == 0.0) {
TotalBodys--;
SetAPen(rp,BLKPEN);
WritePixel(rp,x,y);
MSG("Mass can't be ZERO!!","OK","OK");
return(0);
};
Bodys[CurBody].x = (double)(x)*SI.ds;
Bodys[CurBody].y = (double)(y)*SI.ds;
Bodys[CurBody].real = 1;
SetAPen(rp,Bodys[CurBody].pen);
WritePixel(rp,x,y);
return(0);
}
FindFreeBody()
{
int x;
for(x=0 ; x<MAXBODYS ; x++)
if(!Bodys[x].real) return(x);
return(-1);
}
ModifyBodys()
{
int n;
SHORT x,y;
mode = MODE_MODIFY;
ModifyIDCMP(w,IDCMPFL);
ClosePw();
OffMenu(w,MN_CStart);
OffMenu(w,MN_EMod);
OffMenu(w,MN_ECreate);
cancel_text.IText = deltxt;
for(n=0 ; n<MAXBODYS ; n++) {
CurBody = n;
if(Bodys[n].real) {
Bodys[n].real=0;
LoadBodyReq(n);
x = (SHORT)(Bodys[n].x/SI.ds);
y = (SHORT)(Bodys[n].y/SI.ds);
color_text.FrontPen = Bodys[n].pen;
sprintf(xy_buf," %.3e , %.3e ",
(double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
Request(&BodyInfo,w);
Sleep(0L,100000L);
ReqActive = ReqBody;
ActivateGadget(&name,w,&BodyInfo);
DoIntuiEvents(NOWAIT);
if(CancelHit) { /* GAD really says "DELETE" */
TotalBodys--;
SetAPen(rp,BLKPEN);
WritePixel(rp,x,y);
continue;
};
GetBodyInfo();
if(Bodys[n].Mass == 0.0) {
TotalBodys--;
SetAPen(rp,BLKPEN);
WritePixel(rp,(SHORT)x,(SHORT)y);
MSG("Mass can't be ZERO!!","OK","OK");
continue;
};
Bodys[n].real=1;
SetAPen(rp,Bodys[CurBody].pen);
WritePixel(rp,x,y);
};
};
color_text.FrontPen = WHTPEN;
OnMenu(w,MN_CStart);
OnMenu(w,MN_ECreate);
if(TotalBodys)
OnMenu(w,MN_EMod);
else
OffMenu(w,MN_EMod);
return(0);
}
LoadBodyReq(n)
int n;
{
double v;
name_txstr.NumChars = sprintf(name_sbuf,"%s",Bodys[n].name);
mass_txstr.NumChars = sprintf(mass_sbuf,"%.3e",Bodys[n].Mass);
direction_txstr.LongInt = (ULONG)(Bodys[n].Dir * 180.0/PI);
direction_txstr.NumChars = sprintf(direction_sbuf,"%ld",
direction_txstr.LongInt);
v = Bodys[n].Vx*Bodys[n].Vx + Bodys[n].Vy*Bodys[n].Vy;
v = sqrt(v);
velocity_txstr.NumChars = sprintf(velocity_sbuf,"%.3e",v);
if(Bodys[n].fixed) {
fixed.GadgetText = &yes_text;
fixed.Flags |= SELECTED;
} else {
fixed.GadgetText = &no_text;
fixed.Flags &= ~SELECTED;
}
return(0);
}
DoSimulation()
{
UBYTE b;
double F,Fx=0.0,Fy=0.0,V;
Et = 0L;
while(mode == MODE_START) {
if(SI.ShowTime) {
sprintf(pbuf," Time %ld",Et);
PrintIText(prp,&pos_txt,0,0);
};
/*
* Calculate new directions & velocities
* resulting from all external forces (all other bodies)
*/
for(b=0 ; b<MAXBODYS ; b++ ) {
if(!Bodys[b].real) continue;
if(Bodys[b].fixed) continue;
GetForces(b,&Fx,&Fy);
if(Fx != 0.0 && Fy != 0.0) {
F = sqrt(Fx*Fx+Fy*Fy); /* Total force on this body */
/* indirection of A */
V = F*SI.dt/Bodys[b].Mass; /* FT = MV (impulse) */
Bodys[b].Vx += V*Fx/F; /* Fx/F = cos(A). adj vel as a result of impulse */
Bodys[b].Vy += V*Fy/F; /* Fy/F = sin(A). in direction of resultant Force */
Bodys[b].Dir = atan2(Bodys[b].Vy,Bodys[b].Vx); /* new direction */
if(Bodys[b].Dir < 0.0)
Bodys[b].Dir += 2.0*PI;
};
};
/*
* Display new positions
*/
for(b=0 ; b<MAXBODYS ; b++) {
if(!Bodys[b].real) continue;
if(!SI.TrailLength) {
SetAPen(rp,BLKPEN);
WritePixel(rp,(SHORT)(Bodys[b].x/SI.ds),(SHORT)(Bodys[b].y/SI.ds));
} else {
if(SI.TrailLength>0) {
if(Bodys[b].TrailIDX >= SI.TrailLength)
Bodys[b].TrailIDX=0;
if(Bodys[b].TrailX[Bodys[b].TrailIDX]>=0) {
SetAPen(rp,BLKPEN);
WritePixel(rp,(SHORT)(Bodys[b].TrailX[Bodys[b].TrailIDX]/SI.ds),
(SHORT)(Bodys[b].TrailY[Bodys[b].TrailIDX]/SI.ds));
};
Bodys[b].TrailX[Bodys[b].TrailIDX] = Bodys[b].x;
Bodys[b].TrailY[Bodys[b].TrailIDX] = Bodys[b].y;
Bodys[b].TrailIDX++;
};
};
Bodys[b].x += (Bodys[b].Vx * SI.dt);
Bodys[b].y -= (Bodys[b].Vy * SI.dt);
SetAPen(rp,Bodys[b].pen);
WritePixel(rp,(SHORT)(Bodys[b].x/SI.ds),(SHORT)(Bodys[b].y/SI.ds));
};
DoIntuiEvents(NOWAIT);
if(SI.t)
Sleep(0L,(ULONG)SI.t*1000L);
Et++;
};
return(0);
}
GetForces(b,fx,fy)
UBYTE b;
double *fx,*fy;
{
int x;
double dY,dX,Fx,Fy,F,R;
Fx = Fy = 0.0;
for(x=0 ; x<MAXBODYS ; x++) {
if(x==b) continue;
if(!Bodys[x].real) continue;
dX = (Bodys[x].x - Bodys[b].x) * SI.ds; /* X2 - X1 */
dY = (Bodys[b].y - Bodys[x].y) * SI.ds; /* Y2 - Y1 BUT */
/* normalized to bottom */
/* left of window */
R = dX*dX+dY*dY; /* part of sqrt(x^2+y^2) */
/* for F calc below. F needs R^2 so we'll */
/* do sqrt() part after (sqrt(x)^2 = x) */
F = SI.G * (Bodys[b].Mass * Bodys[x].Mass) / R;
R = sqrt(R); /* distance between points */
Fx += F*(dX/R); /* dX/R = cos(A) but faster */
Fy += F*(dY/R); /* dY/R = sin(A) but faster */
};
*fx = Fx;
*fy = Fy;
return(0);
}
SetupGADefaults()
{
strcpy(G_sbuf,"6.67e0");
G_txstr.NumChars=6;
strcpy(t_sbuf,"0");
t_txstr.NumChars=1;
t_txstr.LongInt = 0L;
strcpy(ds_sbuf,"1.0e0");
ds_txstr.NumChars=5;
strcpy(dt_sbuf,"1.0e0");
dt_txstr.NumChars=5;
strcpy(tl_sbuf,"0");
dt_txstr.NumChars=1;
st.GadgetText = &no_text;
st.Flags &= ~SELECTED;
return(0);
}
BodyGADefaults()
{
strcpy(name_sbuf,"SUN");
name_txstr.NumChars=3;
strcpy(mass_sbuf,"1.0e0");
mass_txstr.NumChars=5;
strcpy(velocity_sbuf,"0.0e0");
velocity_txstr.NumChars=5;
strcpy(direction_sbuf,"0");
direction_txstr.NumChars=1;
direction_txstr.LongInt = 0L;
fixed.GadgetText = &no_text;
fixed.Flags &= ~SELECTED;
return(0);
}
ClearBodys()
{
int x,t;
for(x=0 ; x<MAXBODYS ; x++) {
Bodys[x].real = 0;
Bodys[x].pen = 0;
for(t=0 ; t<MAXTRAILEN ; t++) {
Bodys[x].TrailX[t]=-1.0;
Bodys[x].TrailY[t]=-1.0;
};
Bodys[x].TrailIDX = 0;
};
ClearScreen();
TotalBodys = 0;
return(0);
}
DoSaveData()
{
int x;
FILE *fp;
Request(&FileName,w);
Sleep(0L,100000L);
ActivateGadget(&fn,w,&FileName);
ReqActive = ReqFile;
DoIntuiEvents(NOWAIT);
if(CancelHit)
return(0);
fp = fopen(fn_sbuf,"w");
if(!fp) {
MSG("Can't open output file!","OK!","OH WELL!");
return(0);
};
fprintf(fp,"--- CM Setup Data ---\n");
fprintf(fp,"G=%.3e\n",SI.G);
fprintf(fp,"ds=%.3e\n",SI.ds);
fprintf(fp,"dt=%.3e\n",SI.dt);
fprintf(fp,"t=%d\n",(int)SI.t);
fprintf(fp,"TrailLength=%d\n",(int)SI.TrailLength);
fprintf(fp,"ShowTime=%d\n",(int)SI.ShowTime);
fprintf(fp,"--- CM Body Data ---\n");
fprintf(fp,"#=name ;pen;fixed;Radius;Mass;x,y;Vx,Vy;Dir\n");
for(x=0 ; x<MAXBODYS ; x++)
if(Bodys[x].real) {
fprintf(fp,"%d=%s ;%d;%d;%ld;%.3e;%.3e,%.3e;%.3e,%.3e;%.3e\n",
x,
Bodys[x].name,
(int)Bodys[x].pen,
(int)Bodys[x].fixed,
Bodys[x].Radius,
Bodys[x].Mass,
Bodys[x].x,w->GZZHeight-Bodys[x].y+1,
Bodys[x].Vx,Bodys[x].Vy,
Bodys[x].Dir*180.0/PI);
};
fclose(fp);
return(0);
}
DoLoadData()
{
int n;
FILE *fp;
char buf[101],name[10];
ULONG pen,fixed,Radius;
double x,y,Mass,Vx,Vy,Dir;
CancelHit=0;
Request(&FileName,w);
Sleep(0L,100000L);
ActivateGadget(&fn,w,&FileName);
ReqActive = ReqFile;
DoIntuiEvents(NOWAIT);
if(CancelHit)
return(0);
fp = fopen(fn_sbuf,"r");
if(!fp) {
MSG("Can't open Data File!","OK!","OH WELL!");
return(0);
};
fgets(buf,100,fp); /* forget first line, it's just a header */
fgets(buf,100,fp);
if(sscanf(buf,"G=%le\n",&SI.G) != 1) {
MSG("Bad data file (G)!","OK!","OOPS!");
fclose(fp);
return(0);
};
fgets(buf,100,fp);
if(sscanf(buf,"ds=%le\n",&SI.ds) != 1) {
MSG("Bad data file (ds)!","OK!","OOPS!");
fclose(fp);
return(0);
};
fgets(buf,100,fp);
if(sscanf(buf,"dt=%le\n",&SI.dt) != 1) {
MSG("Bad data file (dt)!","OK!","OOPS!");
fclose(fp);
return(0);
};
fgets(buf,100,fp);
if(sscanf(buf,"t=%d\n",&n) != 1) {
MSG("Bad data file (t)!","OK!","OOPS!");
fclose(fp);
return(0);
};
SI.t = (UBYTE)n;
fgets(buf,100,fp);
if(sscanf(buf,"TrailLength=%d\n",&n) != 1) {
MSG("Bad data file (TrailLength)!","OK!","OOPS!");
fclose(fp);
return(0);
};
if(n>MAXTRAILEN) {
MSG("TrailLength too big","OK!","OOPS!");
fclose(fp);
return(0);
};
SI.TrailLength = (WORD)n;
fgets(buf,100,fp);
if(sscanf(buf,"ShowTime=%d\n",&n) != 1) {
MSG("Bad data file (ShowTime)!","OK!","OOPS!");
fclose(fp);
return(0);
};
SI.ShowTime = (WORD)n;
if(n) {
st.GadgetText = &yes_text;
st.Flags |= SELECTED;
} else {
st.GadgetText = &no_text;
st.Flags &= ~SELECTED;
};
G_txstr.NumChars = sprintf(G_sbuf,"%.3e",SI.G);
dt_txstr.NumChars = sprintf(dt_sbuf,"%.3e",SI.dt);
t_txstr.NumChars = sprintf(t_sbuf,"%d",SI.t);
t_txstr.LongInt = (ULONG)SI.t;
ds_txstr.NumChars = sprintf(ds_sbuf,"%.3e",SI.ds);
tl_txstr.LongInt = (LONG)SI.TrailLength;
tl_txstr.NumChars = sprintf(tl_sbuf,"%d",SI.TrailLength);
ClearBodys();
fgets(buf,100,fp);
fgets(buf,100,fp);
while(fgets(buf,100,fp) != (char *)NULL) {
if(sscanf(buf,"%d=%s;%d;%d;%ld;%le;%le,%le;%le,%le;%le",
&n,name,&pen,&fixed,&Radius,&Mass,&x,&y,&Vx,&Vy,&Dir) != 11) {
MSG("Bad Body in data file","OK!","OOPS!");
fclose(fp);
return(0);
};
if(n>MAXBODYS) {
MSG("Bad Body # in data file","OK!","OOPS!");
fclose(fp);
return(0);
};
if(!Bodys[n].real) TotalBodys++; /* don't count same definition twice */
Bodys[n].real = 1;
Bodys[n].pen = pen;
Bodys[n].fixed = fixed;
Bodys[n].Radius = Radius;
Bodys[n].Mass = Mass;
Bodys[n].x = x;
Bodys[n].y = w->GZZHeight-y+1;
Bodys[n].Vx = Vx;
Bodys[n].Vy = Vy;
Bodys[n].Dir = Dir*PI/180.0;
strcpy(Bodys[n].name,name);
SetAPen(rp,pen);
WritePixel(rp,(SHORT)(Bodys[n].x/SI.ds),(SHORT)(Bodys[n].y/SI.ds));
};
fclose(fp);
OnMenu(w,MN_ECreate);
OnMenu(w,MN_EMod);
return(0);
}
MSG(msg,p,n)
char *msg,*p,*n;
{
struct IntuiText msg_txt = {
BLKPEN,REDPEN, /* FrontPen, BackPen */
JAM1, /* DrawMode */
10,20, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* TextAttr */
0, /* IText */
NULL /* NextText */
};
struct IntuiText pos_txt = {
BLKPEN,REDPEN, /* FrontPen, BackPen */
JAM1, /* DrawMode */
3,3, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* TextAttr */
0, /* IText */
NULL /* NextText */
};
struct IntuiText neg_txt = {
BLKPEN,REDPEN, /* FrontPen, BackPen */
JAM1, /* DrawMode */
3,3, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* TextAttr */
0, /* IText */
NULL /* NextText */
};
msg_txt.IText = msg;
pos_txt.IText = p;
neg_txt.IText = n;
return(AutoRequest(w,&msg_txt,&pos_txt,&neg_txt,
NULL,NULL,40+IntuiTextLength(&msg_txt),80));
}
Sleep(secs,usecs)
ULONG secs,usecs;
{
TR->tr_node.io_Command = TR_ADDREQUEST;
TR->tr_time.tv_secs = secs;
TR->tr_time.tv_micro = usecs;
DoIO(TR);
return(0);
}
CleanUp()
{
if(TimerPort) DeletePort(TimerPort);
if(TimerOpen) CloseDevice(TR);
if(TR) DeleteExtIO(TR,sizeof(struct timerequest));
if(w) {
ClearMenuStrip(w);
CloseWindow(w);
};
if(pw) CloseWindow(pw);
if(s) {
CloseScreen(s);
/* FreeColorMap(cm); */
};
if(GfxBase) CloseLibrary(GfxBase);
(void)OpenWorkBench();
if(IntuitionBase) CloseLibrary(IntuitionBase);
return(0);
}