home *** CD-ROM | disk | FTP | other *** search
Wrap
(* ############################################################################### # # # Dust V1.04 - Copyright ©1994 by A.Maschke # # All rights reserved. # #-----------------------------------------------------------------------------# # # # Tutorial 3: Create a particle-explosion using Dust # # -changes only particle-positions # # -writes scriptfile to stdout # # # # OPERATION: 1. write a script which creates a particle-object and outputs # # the PPOS-array and OCOUNT, e.g.: # # "load(1,objects/s1) # # load(2,objects/c1) # # o2p(1,2,1,p) # # savep(1,PExample.obj) # # getocount(1) # # !copy T:Dust.output PExample.oCount # # getppos(1) # # !copy T:Dust.output PExample.PPOS # # !delete T:Dust.output # # exit" # # 2. execute this script using Dust # # 3. execute this programm writing "PExample >pex.bat" # # 4. execute the created file "pex.bat" using Dust" # # 5. That's it (You got 12 particle objects). # # # #-----------------------------------------------------------------------------# # # # Language: OBERON 2 # # Compiler: Amiga OBERON V3.2 # # Last modified: 23 September 1994 # # # ############################################################################### *) (*******************************************************************************) (* NOTE: This code is Public Domain. You can do what you want with it. *) (*******************************************************************************) MODULE PExample; IMPORT io, Break, SYS:SYSTEM, ST:Strings, RND:Random, ML:MATHLIB, MT:MathTrans, Dos, Exec; (* Notes for C-Programmers: "IMPORT" means here "#include" io: stdio.h Break: not necessary SYS: not necessary ( "SYS.ADR(xy)" means "&xy" ) ST: string-operations ( needed to generate filenames like "obj.0521" ) RND: compute random-numbers (stdlib.h ?) ML: math.h MT: math.h Dos: you will know ( "Dos.ReadAPTR()" means "Read()" ) Exec: "" *) CONST ZERO=0.0001; TYPE STRING=ARRAY 256 OF CHAR; TYPE Vector=STRUCT x,y,z:REAL; END; TYPE VP=POINTER TO ARRAY OF Vector; VAR EXFILE:STRING; (* filename for the external data *) oCount:INTEGER; (* number of particles (to be read) *) pos:VP; (* particle positions (to be read) *) bb:REAL; (* needed by RND2() *) (*******************************************************************************) (* some OBERON-specific procedures ( implement them in another way *) (*******************************************************************************) (* converts digit into CHAR *) PROCEDURE gs(lt:LONGINT):CHAR; BEGIN CASE lt OF 0:RETURN '0' | 1:RETURN '1' | 2:RETURN '2' | 3:RETURN '3' | 4:RETURN '4' | 5:RETURN '5' | 6:RETURN '6' | 7:RETURN '7' | 8:RETURN '8' | 9:RETURN '9' ELSE RETURN '0' END; END gs; (* converts INTEGER into ARRAY OF CHAR (aim: no spaces) *) PROCEDURE IntToString(lt:LONGINT;VAR str:STRING); VAR lt2,len,i,ll,dd:LONGINT; sig:BOOLEAN; BEGIN IF lt<0 THEN sig:=TRUE ELSE sig:=FALSE END;lt2:=ABS(lt); IF lt2=0 THEN str:="0";RETURN; (* fastest way (log10 doesn't work at 10,100,... !)*) ELSIF lt2=10 THEN str:="10";ELSIF lt2=100 THEN str:="100"; ELSIF lt2=1000 THEN str:="1000";ELSIF lt2=10000 THEN str:="10000"; ELSIF lt2=100000 THEN str:="100000";ELSIF lt2=1000000 THEN str:="1000000"; ELSIF lt2=10000000 THEN str:="10000000";ELSIF lt2=100000000 THEN str:="100000000"; ELSIF lt2=1000000000 THEN str:="1000000000"; ELSE len:=ENTIER(ML.LOG10(lt2))+1;dd:=1; IF len>1 THEN i:=1; REPEAT dd:=dd*10; INC(i); UNTIL i>=len; ELSE str[0]:=gs(lt2); str[1]:='\o'; IF sig THEN ST.InsertChar(str,0,'-') END; RETURN; END; i:=0; REPEAT ll:=lt2 DIV dd; lt2:=lt2 MOD dd; dd:=dd DIV 10; str[i]:=gs(ll); INC(i); UNTIL i>=len; str[len]:='\o'; END; IF sig THEN ST.InsertChar(str,0,'-') END; END IntToString; (* writes an INTEGER to stdout *) PROCEDURE WriteInt(lt:LONGINT); VAR hs:STRING; BEGIN IntToString(lt,hs); io.WriteString(hs); END WriteInt; (* converts REAL into ARRAY OF CHAR (aim: no spaces, upto 4 digits after the point *) PROCEDURE RealToString(rt:REAL;VAR str2:STRING); VAR rt2:REAL; sig:BOOLEAN; hs:STRING; lt1,lt2,lt3:LONGINT;BEGIN IF rt=0.0 THEN str2:="0";RETURN END; IF rt<0.0 THEN sig:=TRUE ELSE sig:=FALSE END; rt2:=ABS(rt); lt1:=ENTIER(rt2); IntToString(lt1,str2); rt2:=rt2-lt1; IF rt2>=0.00005 THEN rt2:=rt2*10000.0; lt2:=ENTIER(rt2+0.5); IF lt2>=9999 THEN INC(lt1); IntToString(lt1,str2); ELSE ST.Append(str2,"."); lt3:=1; IF (lt2 MOD 10)=0 THEN lt2:=lt2 DIV 10;lt3:=10; END; IF (lt2 MOD 10)=0 THEN lt2:=lt2 DIV 10;lt3:=100; END; IF (lt2 MOD 10)=0 THEN lt2:=lt2 DIV 10;lt3:=1000; END; IntToString(lt2,hs); lt2:=lt2*lt3; IF lt2<10 THEN ST.Append(str2,"000") ELSIF lt2<100 THEN ST.Append(str2,"00") ELSIF lt2<1000 THEN ST.Append(str2,"0") ELSE END; ST.Append(str2,hs); END; END; IF sig THEN IF (str2[0]='0') AND (ST.Length(str2)=1) THEN ELSE ST.InsertChar(str2,0,'-') END; END; END RealToString; (* writes a REAL to stdout *) PROCEDURE WriteReal(rt:REAL); VAR hs:STRING; BEGIN RealToString(rt,hs);io.WriteString(hs); END WriteReal; (* returns a factor between 0.9 and 1.0 *) PROCEDURE RND2*():REAL; BEGIN bb:=RND.RND(901)+100; bb:=bb/10000.0; IF RND.RND(2)=1 THEN RETURN 1.0+bb ELSE RETURN 1.0-bb END; END RND2; (* generates a filename like "obj.0235" *) PROCEDURE GenFn(str1:STRING;VAR str2:STRING;tt:INTEGER); VAR hs:STRING; BEGIN str2:=str1; IntToString(tt,hs); IF tt>=1000 THEN ST.Append(str2,".");ST.Append(str2,hs); ELSIF (tt<1000) AND (tt>=100) THEN ST.Append(str2,".0");ST.Append(str2,hs); ELSIF (tt<100) AND (tt>=10) THEN ST.Append(str2,".00");ST.Append(str2,hs); ELSIF tt<10 THEN ST.Append(str2,".000");ST.Append(str2,hs) END; END GenFn; (*******************************************************************************) (* Read (x,y,z)-array from EXFILE; this example: pos *) (*******************************************************************************) PROCEDURE ReadReal(fn:STRING;VAR vp:VP;count:INTEGER):BOOLEAN; VAR a1,size,buffer:LONGINT; fh:Dos.FileHandlePtr; BEGIN (* allocate the array *) IF vp#NIL THEN DISPOSE(vp) END; SYS.ALLOCATE(vp,count); IF vp=NIL THEN RETURN FALSE END; (* allocate file-buffer *) size:=LONG(count)*12; (* 3*REAL=3*4 *) buffer:=Exec.AllocMem(size,LONGSET{Exec.public}); IF buffer=NIL THEN DISPOSE(vp);RETURN FALSE END; (* read the file *) fh:=Dos.Open(fn,Dos.oldFile); IF fh=NIL THEN DISPOSE(vp);Exec.FreeMem(buffer,size);RETURN FALSE END; a1:=Dos.ReadAPTR(fh,buffer,size); IF Dos.Close(fh) THEN END; IF size#a1 THEN DISPOSE(vp);Exec.FreeMem(buffer,size);RETURN FALSE END; (* copy the buffer into the array *) a1:=SYS.ADR(vp^[0]); Exec.CopyMemAPTR(buffer,a1,size); Exec.FreeMem(buffer,size); RETURN TRUE; END ReadReal; (*******************************************************************************) (* Read a integer from EXFILE; this example: oCount *) (*******************************************************************************) PROCEDURE ReadInt(fn:STRING;VAR i:INTEGER):BOOLEAN; VAR ai:LONGINT; fh:Dos.FileHandlePtr; BEGIN ai:=SYS.ADR(i); fh:=Dos.Open(fn,Dos.oldFile); IF fh=NIL THEN RETURN FALSE END; IF Dos.ReadAPTR(fh,ai,2)#2 THEN IF Dos.Close(fh) THEN END;RETURN FALSE END; IF Dos.Close(fh) THEN END; RETURN TRUE; END ReadInt; (*******************************************************************************) (* Call the SETPxxx-Procedure of Dust to change the vector vp^[ind]; *) (* this example: SETPPOS(1,ind,pos^[ind].x,pos^[ind].x,pos^[ind].z) *) (*******************************************************************************) PROCEDURE WritePXXX(x,y,z:REAL;ind:INTEGER;cmd:STRING); BEGIN io.WriteString("\nSETP"); io.WriteString(cmd); io.WriteString("(1,"); WriteInt(ind); io.WriteString(","); WriteReal(x); io.WriteString(","); WriteReal(y); io.WriteString(","); WriteReal(z); io.WriteString(")"); END WritePXXX; (*******************************************************************************) (* Main procedure *) (* Arguments: frames: number of objects (frames) fn: base filename of the objects timep: time to process gp: gravity constant, e.g. -10.0 (negative) etap: friction (Stokes), e.g. -0.00001 (negative) vv0p: speed at t=0 (positive) fmt: save-format-string, e.g. "TDDD" *) (*******************************************************************************) PROCEDURE DoIt(frames:INTEGER;fn:STRING;timep,gp,etap,vv0p:REAL;fmt:STRING); VAR fn2:STRING; v0:VP; i,j:INTEGER; oldX,oldY:POINTER TO ARRAY OF REAL; eta,g,vv0,time,timestep,t,A,Ae,Aet,V0,X0:REAL; centreX,centreY,centreZ:REAL; dx,dy,dz,vb,cx,cy,cz,newX,newY,newZ:REAL; (*******************************************************************************) (* calculates centre of all poarticles *) (*******************************************************************************) PROCEDURE getCentre; VAR xmin,xmax,ymin,ymax,zmin,zmax:REAL; BEGIN xmin:=pos^[0].x;xmax:=xmin;ymin:=pos^[0].y;ymax:=ymin;zmin:=pos^[0].z;zmax:=zmin; i:=1; REPEAT IF xmin>pos^[i].x THEN xmin:=pos^[i].x END;IF xmax<pos^[i].x THEN xmax:=pos^[i].x END; IF ymin>pos^[i].y THEN ymin:=pos^[i].y END;IF ymax<pos^[i].y THEN ymax:=pos^[i].y END; IF zmin>pos^[i].z THEN zmin:=pos^[i].z END;IF zmax<pos^[i].z THEN zmax:=pos^[i].z END; INC(i); UNTIL i>=oCount; centreX:=xmin+(xmax-xmin)/2.0; centreY:=ymin+(ymax-ymin)/2.0; centreZ:=zmin+(zmax-zmin)/2.0; (* move the object into the positive z-space if necessary *) IF (zmin<0) AND (g#0.0) THEN xmin:=1.1*zmin; i:=0; REPEAT pos^[i].z:=pos^[i].z-xmin; INC(i); UNTIL i>=oCount; zmin:=zmin-xmin; zmax:=zmax-xmin; (* update centreX *) centreZ:=zmin+(zmax-zmin)/2.0; (* change the original object *) io.WriteString("\n;move the object into the positive z-space"); i:=0; REPEAT WritePXXX(pos^[i].x,pos^[i].y,pos^[i].z,i,"POS"); INC(i); UNTIL i>=oCount; END; END getCentre; BEGIN IF (frames<1) THEN RETURN END; (* allocate some arrays *) SYS.ALLOCATE(v0,oCount);IF v0=NIL THEN RETURN END; SYS.ALLOCATE(oldX,oCount);IF oldX=NIL THEN DISPOSE(v0);RETURN END; SYS.ALLOCATE(oldY,oCount);IF oldY=NIL THEN DISPOSE(oldX);DISPOSE(v0);RETURN END; time:=timep; g:=gp; eta:=etap; vv0:=vv0p; IF g>0.0 THEN g:=-10.0 END; IF vv0<ZERO THEN vv0:=1.0 END; IF eta>=0.0 THEN eta:=-0.00001 END; getCentre; (* compute speed at t=0 (vectors) *) i:=0; REPEAT dx:=pos^[i].x-centreX; dy:=pos^[i].y-centreY; dz:=pos^[i].z-centreZ; vb:=MT.Sqrt(dx*dx+dy*dy+dz*dz); v0^[i].x:=dx/vb*vv0*RND2(); v0^[i].y:=dy/vb*vv0*RND2(); v0^[i].z:=dz/vb*vv0*RND2(); INC(i); UNTIL i>=oCount; (* generate filename and say "save it" (first and unchanged object) *) GenFn(fn,fn2,1); IF fmt="TDDD" THEN io.WriteString("\nSavePTDDD(1,"); ELSIF fmt="VS" THEN io.WriteString("\nSavePVS(1,"); ELSE io.WriteString("\nSaveP(1,"); END; io.WriteString(fn2);io.WriteString(")"); (* main loop *) timestep:=time/(frames-1); i:=1; REPEAT (* output frame as comment *) io.WriteString("\n;frame ");WriteInt(i); t:=i*timestep; (* actual time *) j:=0; REPEAT (* particle-size (friction) (to calculate this the array PSCL is needed) *) A:=RND2()*10.0; Ae:=A*eta; Aet:=Ae*t; (* compute x-coordinate *) V0:=v0^[j].x; X0:=pos^[j].x; cx:=(X0*Ae-V0+V0*MT.Exp(Aet))/(Ae); (* compute y-coordinate *) V0:=v0^[j].y; X0:=pos^[j].y; cy:=(X0*Ae-V0+V0*MT.Exp(Aet))/(Ae); (* compute x-coordinate *) V0:=v0^[j].z; X0:=pos^[j].z; cz:=(X0*Ae*Ae-g-V0*Ae+g*MT.Exp(Aet)+V0*Ae*MT.Exp(Aet)-g*t*Ae)/(Ae*Ae); (* motion must stop at z=0 *) IF cz>0.0 THEN oldX^[j]:=cx; oldY^[j]:=cy; ELSE cz:=0.0; IF i>1 THEN cx:=oldX^[j]; cy:=oldY^[j]; ELSE oldX^[j]:=cx; oldY^[j]:=cy; END; END; (* the final posion *) newX:=cx; newY:=cy; newZ:=cz; (* say: "apply them" *) WritePXXX(newX,newY,newZ,j,"POS"); INC(j); UNTIL j>=oCount; (* generate filename and say "save it" *) GenFn(fn,fn2,i+1); IF fmt="TDDD" THEN io.WriteString("\nSavePTDDD(1,"); ELSIF fmt="VS" THEN io.WriteString("\nSavePVS(1,"); ELSE io.WriteString("\nSaveP(1,"); END; io.WriteString(fn2); io.WriteString(")"); INC(i); UNTIL i>=frames; (* clean up *) DISPOSE(oldY);DISPOSE(oldX); DISPOSE(v0); END DoIt; BEGIN (* load the ppos-array *) IF ReadInt("PEXAMPLE.OCOUNT",oCount) AND ReadReal("PEXAMPLE.PPOS",pos,oCount) THEN (* tell Dust to load the Source-Particle-Object *) io.WriteString("\nloadp(1,PExample.obj)"); (* do it !*) DoIt(12,"obj",12.8,-10.0,-0.001,52,"TDDD"); (* important*) io.WriteString("\n"); DISPOSE(pos); ELSE io.WriteString("\nCouldn't open input-file(s).\n"); END; END PExample.