for Gallery read

    Star demo

    A 3D "star" composed of 100 triangular semi-transparent "rays". The more a ray is in the back, the more it is transparent, in order to percieve easily which ones are in the front. Moving the mouse from left to right rotate the star. Moving up and down scales the star.

    This is the first Lew test I ever wrote.

    Dislay the source code...

      Branches=100; Radius=200; CenterX=320; CenterY=240; Opa=255; Lat ={}; Lon ={}; Lat2={}; Lon2={}; for i=0,Branches,1 do Lat [i]=math.random(0,2*3.141592654*100)/100; Lon [i]=math.random(-0.5*3.141592654*100,0.5*3.141592654*100)/100; Lat2[i]=Lat[i]+math.random(-200,200)/1000; Lon2[i]=Lon[i]+math.random(-200,200)/1000; end Win=OpenWindow(640,480,"Star demo"); Bmp=CreateBitmap(640,480); IncLat=0; for zz=0,2*3.14*10,3.14/5000 do Mousex,Mousey,Mouseb=Mouse(Win); IncLon=-Mousex/640*2*3.141592654; Radius= Mousey/480*200; if (Radius<10) then Radius=10; end -- Opa=Mousey/480*255; -- if (Opa<10) then Opa=10; end -- IncLat=-Mousey/480*2*3.141592654; Ink(0,0,0); Opacity(Opa); RectFill(Bmp,0,0,640,480); for i=0,Branches,1 do x =Radius*math.sin(Lat [i]+IncLat)*math.cos(Lon [i]+IncLon); y =Radius*math.sin(Lat [i]+IncLat)*math.sin(Lon [i]+IncLon); z =Radius*math.cos(Lat [i]+IncLat); xx=Radius*math.sin(Lat2[i]+IncLat)*math.cos(Lon2[i]+IncLon); yy=Radius*math.sin(Lat2[i]+IncLat)*math.sin(Lon2[i]+IncLon); zz=Radius*math.cos(Lat2[i]+IncLat); Opacity(((1+yy/Radius)*20+20)*Radius/200); Ink(220,159,100); TriangleFill(Bmp,CenterX,CenterY,CenterX+x,CenterY+z,CenterX+xx,CenterY+zz); Opacity(((1+yy/Radius)*80+80)*Radius/200); Ink(100,159,220); Triangle(Bmp,CenterX,CenterY,CenterX+x,CenterY+z,CenterX+xx,CenterY+zz); end DisplayBitmap(Bmp,Win); end

    Pshhht demo

    As you drag the mouse it launches dots in slowly evoluting random colors. These dots moves away from the mouse keeping their initial speed, leaves a trail behind them, grow larger and more transparent as they grow "older", and eventually bounces on the window borders.

    Dislay the source code...

      BallsQtt=1000; Gravity=0.00; Amort =0.999; x={}; y={}; vx={}; vy={}; rr={}; gg={}; bb={}; for i=0,BallsQtt,1 do x[i]=0; y[i]=0; vx[i]=0; vy[i]=0; rr[i]=255; gg[i]=255; bb[i]=255; end n=0; Bmp=CreateBitmap(640,480); Window=OpenWindow(640,480,"Balls"); r=255; g=255; b=255; for frame=0,10000,1 do -- pas encore de CLS :-) Ink(0,0,0); Opacity(10); RectFill(Bmp,0,0,640,480); r=r+(math.random(0,200)-100)/10; g=g+(math.random(0,200)-100)/10; b=b+(math.random(0,200)-100)/10; if (r<0) then r=0; end if (g<0) then g=0; end if (b<0) then b=0; end if (r>255) then r=255; end if (g>255) then g=255; end if (b>255) then b=255; end for i=0,BallsQtt,1 do if (not ((x[i]==0) and (y[i]==0))) then x[i]=x[i]+vx[i]; y[i]=y[i]+vy[i]; vx[i]=vx[i]*Amort; vy[i]=vy[i]*Amort-Gravity; if (x[i]<= 5) then vx[i]=math.abs(vx[i]); end if (x[i]>=635) then vx[i]=-math.abs(vx[i]); end if (y[i]<5 ) then vy[i]=math.abs(vy[i]); y[i]=math.abs(y[i]); end if (n>i) then d=BallsQtt-n+i; end if (n<=i) then d=i-n; end Ink(rr[i],gg[i],bb[i]); Opacity(d/BallsQtt*250/2); CircleFill(Bmp,x[i],y[i],10-d/BallsQtt*10+1); end end MX,MY,MB=Mouse(Window); MVX,MVY=MouseSpeed(Window); if (not(MB==0)) then for i=0,10,1 do x[n]=MX; y[n]=MY; vx[n]=math.random(-100,100)/100+MVX/4; vy[n]=math.random(-100,100)/100+MVY/4; rr[n]=r; gg[n]=g; bb[n]=b; n=n+1; if (n>999) then n=0; end end end DisplayBitmap(Bmp,Window); end

    Elastic demo

    Demo of bitmap manipulation: drags will move the bitmap content under the mouse. The use of various circular blurred masks (computed in the program) allows a "natural" deformation of the image.

    Please note that the elastic script is there for reference, but needs a input bitmap file to work. You can download the full set of demos (including this one) here.

    Dislay the source code...

      Masks={}; ElasticRadius=50; for i=0,10,1 do Masks[i]=CreateBitmap(ElasticRadius*2,ElasticRadius*2); Ink(0,0,0); RectFill(Masks[i],0,0,ElasticRadius*2,ElasticRadius*2); RadiusIn =ElasticRadius-i*(0.09*ElasticRadius); RadiusOut=ElasticRadius-(i+1)*(0.09*ElasticRadius); for j=0,10,1 do Ink((j+1)/11*254,(j+1)/11*254,(j+1)/11*254); CircleFill(Masks[i],ElasticRadius,ElasticRadius,(1-j/10)*RadiusIn+(j/10)*RadiusOut); end --Win=OpenWindow(ElasticRadius*2,ElasticRadius*2,tostring(i)); --DisplayBitmap(Masks[i],Win); end Bmp=LoadBitmap("fang.bmp"); Win=OpenWindow(BmpWidth(Bmp),BmpHeight(Bmp),"Ellasticity"); DisplayBitmap(Bmp,Win); oldb=0; while(1==1) do x,y,b=Mouse(Win); y=y; if ((x>ElasticRadius) and (x<BmpWidth(Bmp)-ElasticRadius) and (x>ElasticRadius) and (y<BmpHeight(Bmp)-ElasticRadius)) then if ((not (b==0)) and (oldb==0)) then SampleBmp=Crop(Bmp,x-ElasticRadius,y-ElasticRadius,ElasticRadius*2,ElasticRadius*2); SampleX=x; SampleY=y; end if ((not (b==0)) and (not (oldb==0))) then d=math.sqrt((x-SampleX)*(x-SampleX)+(y-SampleY)*(y-SampleY))+1; for i=0,10,10/d do Pc=i/10; Mix(Bmp,x*(Pc)+SampleX*(1-Pc)-ElasticRadius,y*(Pc)+SampleY*(1-Pc)-ElasticRadius,SampleBmp,Masks[math.floor(i)]); end end DisplayBitmap(Bmp,Win); oldb=b; end end

    Log viewer demo

    A log viewer using similar information visualisation techniques than used in Digg labs. Discs represents web pages, with visitors on the sides. The more visitors, the larger the disc. Of course, if visitors do go away the disc decrease in size. Discs tends to repells each other to cover the screen. Large discs tends to go in the center of the screen. Pages with less than 4 visitors are dusts in the background, and when the pointer hover over a disk, its ID is displayed (together with the ID's of neighboring disks in transparent shades).

    Please note that the log viewer script is there for reference, but needs a font file and a log file to work. You can download the full set of demos (including this one) here.

    Dislay the source code...

      function DrawBall(Bmp,x,y,Weight,Age) local d,o; if (Weight>UnderWeight) then if ((Age<120) and (1==0)) then d=(120-Age)/120*4; Opacity(20); Ink(0,0,0); Thickness(3); Circle(Bmp,x+d,y-d,5+Weight); Thickness(1); for i=0,Weight,1 do Circle(Bmp,x+(5+Weight+4)*math.sin(2*3.1416/Weight*i)+d,y+(5+Weight+4)*math.cos(2*3.1416/Weight*i)-d,2); end end o=255-Age/(120)*200; if (o<30) then o=30 end Opacity(o); Ink(255,0,0); Thickness(3); Circle(Bmp,x,y,5+Weight); Thickness(1); for i=0,Weight,1 do Circle(Bmp,x+(5+Weight+4)*math.sin(2*3.1416/Weight*i),y+(5+Weight+4)*math.cos(2*3.1416/Weight*i),2); end else Opacity(50); Ink(150,0,0); Circle(Bmp,x,y,Weight); -- Line(Bmp,x-Weight,y,x+Weight,y); -- Line(Bmp,x,y-Weight,x,y+Weight); end end function DrawTag(Bmp,x,y,Weight,Opac,String) local w; local h; local i; -- draw the tag if (not(String=="")) then w,h=TextSize(String); w=w+10; Opacity(80*Opac/256); Ink(0,0,0); RectangleFill(Bmp,x-w/2+3,y+10-3+5,w,h); TriangleFill(Bmp,x,y+5,x-2+3,y+10-3+5,x+2+3,y+10-3+5); Opacity(255*Opac/256); Ink(255,255,255); RectangleFill(Bmp,x-w/2,y+10+5,w,h); TriangleFill(Bmp,x,y+5,x-2,y+10+5,x+2,y+10+5); Opacity(150*Opac/256); Ink(255,0,0); Line(Bmp,x ,y +5, x-2 ,y+10 +5); Line(Bmp,x-2 ,y+10 +5, x-w/2,y+10 +5); Line(Bmp,x-w/2,y+10 +5, x-w/2,y+10+h+5); Line(Bmp,x-w/2,y+10+h+5, x+w/2,y+10+h+5); Line(Bmp,x+w/2,y+10+h+5, x+w/2,y+10 +5); Line(Bmp,x+w/2,y+10 +5, x+2 ,y+10 +5); Line(Bmp,x+2 ,y+10 +5, x ,y +5); Opacity(255*Opac/256); TextAlign(-0.5); TextVAlign(-1); Text(Bmp,x,y+10+5,String); end end function DrawAll(CrntTime) local x,y,b,i,dx,dy,d,hh,mm,ss; -- clear screen Ink(220,220,220); Opacity(255); RectFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); -- draw grid Opacity(10); Ink(0,0,0); for i=0,BmpWidth(Bmp),15 do Line(Bmp,i,0,i,BmpHeight(Bmp)); end for i=0,BmpHeight(Bmp),15 do Line(Bmp,0,i,BmpWidth(Bmp),i); end Opacity(10); Ink(0,0,0); for i=0,BmpWidth(Bmp),15*4 do Line(Bmp,i,0,i,BmpHeight(Bmp)); end for i=0,BmpHeight(Bmp),15*4 do Line(Bmp,0,i,BmpWidth(Bmp),i); end -- draw time CrntTimeString=string.format("%02i:%02i:%02i",math.floor(CrntTime/3600),math.floor(CrntTime/60)%60,CrntTime%60); TextAlign(0); TextVAlign(-1); Opacity(255); Text(Bmp,10,10,CrntTimeString); x,y,b=Mouse(Wnd); -- draw circles for i=0,PtQtt,1 do if (Weight[i]>0) then DrawBall(Bmp,px[i],py[i],Weight[i],CrntTime-Last[i]); end end -- draw shaded labels for i=0,PtQtt,1 do if (Weight[i]>UnderWeight) then dx=x-px[i]; dy=y-py[i]; d=math.sqrt(dx*dx+dy*dy); if ((d>=20) and (d<100)) then DrawTag(Bmp,px[i],py[i],Weight[i],50,Name[i]); end end end -- draw plain labels for i=0,PtQtt,1 do if (Weight[i]>UnderWeight) then dx=x-px[i]; dy=y-py[i]; d=math.sqrt(dx*dx+dy*dy); if ((d<20) and (d<100)) then DrawTag(Bmp,px[i],py[i],Weight[i],255,Name[i]); end end end DisplayBitmap(Bmp,Wnd); end function KillOlds(CrntTime) local i,j,EvntTime,h; for i=0,PtQtt,1 do if (Weight[i]>0) then h=""; for EvntTime in string.gmatch(History[i],"%d+") do if ((1*EvntTime)<CrntTime-5*60) then Weight[i]=Weight[i]-1; else h=h..EvntTime.." "; end end History[i]=h; end end end function UpdatePositions() local i,j; for i=0,PtQtt,1 do ax[i]=0; ay[i]=-Gravity; if (Weight[i]>UnderWeight) then --- dots have a tendency to avoid each others for j=0,PtQtt,1 do if ((not (i==j))and(Weight[j]>UnderWeight)) then dx=px[j]-px[i]; dy=py[j]-py[i]; d=math.sqrt(dx*dx+dy*dy); dx=-dx/d; dy=-dy/d; if (d<RepellRadius) then ax[i]=ax[i]+dx*(RepellRadius-d)/5/(Weight[i]); ay[i]=ay[i]+dy*(RepellRadius-d)/5/(Weight[i]); end end end --- dots are repelled by the screen border if (px[i]<RepellRadius) then ax[i]=ax[i]+px[i]/10/Weight[i]; end if (py[i]<RepellRadius) then ay[i]=ay[i]+py[i]/10/Weight[i]; end if (px[i]>BmpWidth (Bmp)-RepellRadius) then ax[i]=ax[i]-(BmpWidth (Bmp)-px[i])/10/Weight[i]; end if (py[i]>BmpHeight(Bmp)-RepellRadius) then ay[i]=ay[i]-(BmpHeight(Bmp)-py[i])/10/Weight[i]; end --- heavy dots have a tendency to go in the center of the screen ax[i]=ax[i]+((BmpWidth (Bmp))/2-px[i])/BmpWidth(Bmp) *Weight[i]; ay[i]=ay[i]+((BmpHeight(Bmp))/2-py[i])/BmpHeight(Bmp)*Weight[i]; for i=0,PtQtt,1 do vx[i]=(vx[i]+ax[i])*Amort; vy[i]=(vy[i]+ay[i])*Amort; end for i=0,PtQtt,1 do px[i]=px[i]+vx[i]; py[i]=py[i]+vy[i]; if (px[i]<10 ) then px[i]=10; vx[i]=0; end if (px[i]>BmpWidth(Bmp)-10 ) then px[i]=BmpWidth(Bmp)-10; vx[i]=0; end if (py[i]<10 ) then py[i]=10; vy[i]=0; end if (py[i]>BmpHeight(Bmp)-10) then py[i]=BmpHeight(Bmp)-10; vy[i]=0; end end end end end Fnt=LoadFont("arial_s.bmp"); Bmp=CreateBitmap(800,600); Wnd=OpenWindow(BmpWidth(Bmp),BmpHeight(Bmp),"Text"); px={}; py={}; vx={}; vy={}; ax={}; ay={}; Weight={}; Name={}; id2num={}; History={}; Last={}; UnderWeight=3; Amort=0.05; Gravity=0.0; RepellRadius=150; PtQtt=1000; MaxPt=1000; for i=0,MaxPt,1 do px[i]=0; py[i]=0; vx[i]=0; vy[i]=0; ax[i]=0; ay[i]=0; Weight[i]=0; Name[i]=""; History[i]=""; Last[i]=0; end CrntTime=1; for Line in io.lines("log/log_2008_01_30.txt") do hh,mm,ss=string.match(Line,"(%d%d):(%d%d):(%d%d)"); FileTime=ss+60*mm+3600*hh; --Alert(FileTime); while (FileTime>CrntTime) do KillOlds(CrntTime); UpdatePositions(); DrawAll(CrntTime); CrntTime=CrntTime+1; end id=string.match(Line,"(%d%d%d%d%d%d%d_%a+)"); if (not(id==nil)) then if ((id2num[id]=="")or(id2num[id]==nil)) then BestCandidate=0; for i=0,MaxPt,1 do if (Weight[i]<Weight[BestCandidate]) then BestCandidate=i; end end px[BestCandidate]=math.random(0,BmpWidth(Bmp)); py[BestCandidate]=math.random(0,BmpHeight(Bmp)); vx[BestCandidate]=0; vy[BestCandidate]=0; ax[BestCandidate]=0; ay[BestCandidate]=0; Weight[BestCandidate]=1; Name[BestCandidate]=id; History[BestCandidate]=History[BestCandidate]..CrntTime.." "; id2num[id]=BestCandidate; Last[BestCandidate]=CrntTime; else Weight[id2num[id]]=Weight[id2num[id]]+1; History[id2num[id]]=History[id2num[id]]..CrntTime.." "; Last[id2num[id]]=CrntTime; end end end

    Ticker demo

    The demo opens a file and display its content in the bottom largest line which flows into a smaller font line, which in turn flows into and smaller line,... Demonstrate bitmap font scaling and transparencies, prediction of text size with non proportional font, and so on.

    Please note that the ticker script is there for reference, but needs a font file and a text file to work. You can download the full set of demos (including this one) here.

    Dislay the source code...

      function PushChar(c,i) local Fonti; if (i<12) then -- compute font for line i Fonti=10-i; if (Fonti<0) then Fonti=0; end if (Lines[i]==nil) then Lines[i]=c else Lines[i]=Lines[i]..c end TextFont(Fnt[Fonti]); while (TextSize(Lines[i])>BmpWidth(Bmp)-20) do PushChar(string.sub(Lines[i],1,1),i+1); Lines[i]=string.sub(Lines[i],2,-1); end end end function DisplayLines() local i; local Fonti; local y; local LineY; y=0; for i=0,11,1 do -- compute font for line i Fonti=10-i; if (Fonti<0) then Fonti=0; end -- compute y for line i LineY=15-i; if (LineY<3) then LineY=3; end y=y+LineY; TextFont(Fnt[Fonti]); Ink(0,80,160); if (Fonti==5) then Ink(255,0,0) end Opacity(255-i/11*200); TextAlign(-0.5); TextVAlign(-1); if (not (Lines[i]==nil)) then Text(Bmp,BmpWidth(Bmp)/2,y,Lines[i]); end end end -- load font and build 10 variants (5 smallers, 5 largers) Fnt={}; Fnt[5]=LoadFont("arial_s.bmp"); for i=1,5,1 do Fnt[5-i]=Resize(Fnt[5],BmpWidth(Fnt[5])-i*BmpWidth(Fnt[5])/10,BmpHeight(Fnt[5])-i*BmpHeight(Fnt[5])/10); Fnt[5+i]=Resize(Fnt[5],BmpWidth(Fnt[5])+i*BmpWidth(Fnt[5])/10,BmpHeight(Fnt[5])+i*BmpHeight(Fnt[5])/10); end Lines={}; Bmp=CreateBitmap(1000,120); Wnd=OpenWindow(BmpWidth(Bmp),BmpHeight(Bmp),"Text"); FileHandle=io.open("texte.txt"); while(1==1) do c=FileHandle:read(1); if (not(c==nil)) then PushChar(c,0); Opacity(255); Ink(255,255,255); RectFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); DisplayLines(); DisplayBitmap(Bmp,Wnd); else exit(); end end

    Radix demo

    Uses a recursive algorythm to build representation of vegetals.

    Dislay the source code...

      Bmp=CreateBitmap(800,800); Wnd=OpenWindow(BmpWidth(Bmp),BmpHeight(Bmp),"Radix demo"); function DrawRadix(x,y,Radix) local xx,yy; local Length; local Width; if (not(Radix==nil)) then Length=math.sqrt(Radix.Age); xx=x+Length*math.sin(Radix.Angle); yy=y+Length*math.cos(Radix.Angle); while (not ((xx>0)and(xx<BmpWidth(Bmp))and(yy>0)and(yy<BmpHeight(Bmp)))) do Radix.Angle=math.random(0,3.141592654*2); xx=x+Length*math.sin(Radix.Angle); yy=y+Length*math.cos(Radix.Angle); end Thickness(math.sqrt(Radix.Age)/3+1); Opacity(Radix.Opacity); --Alert(Radix.Opacity); Ink(50,30,0); Line(Bmp,x,y,xx,yy); if ((not (Radix.ChildrenQtt==nil)) and (Radix.ChildrenQtt>0)) then for i=1,Radix.ChildrenQtt,1 do DrawRadix(xx,yy,Radix.Children[i]); end end if (Radix.Age<10) then Ink(70,255-Radix.Age*30,0) Opacity(50) CircleFill(Bmp,xx,yy,10-Radix.Age); end end end function GrowRadix(Radix) local ChildrenToCreate; local Answer=0; if ((not (Radix.ChildrenQtt==nil)) and (Radix.ChildrenQtt>0)) then for i=1,Radix.ChildrenQtt,1 do Answer=Answer+GrowRadix(Radix.Children[i]); end if (Answer>0) then Radix.Age=Radix.Age+1; end else if (Radix.Opacity>5) then Answer=Answer+1; ChildrenToCreate=1; if (math.random(0,100)>95) then ChildrenToCreate=2 end if (math.random(0,100)>99) then ChildrenToCreate=3 end if (math.random(0,100)>50) then for i=1,ChildrenToCreate,1 do Radix.Children[i]={}; Radix.Children[i].Age=1; Radix.Children[i].Angle=Radix.Angle+(math.random(0,1000)-500)/500/2; Radix.Children[i].ChildrenQtt=0; Radix.Children[i].Children={}; Radix.Children[i].Opacity=Radix.Opacity*(math.random(0,1000)+4200)/5000; end Radix.ChildrenQtt=ChildrenToCreate; end end end return(Answer); end Ink(255,255,255); Opacity(255); RectangleFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); while (1==1) do Radix={}; Radix.Age =1; Radix.Angle =0; Radix.Children ={} Radix.ChildrenQtt=0; Radix.Opacity =255; repeat i=GrowRadix(Radix); until (i<=0); Ink(255,255,255); Opacity(4); RectangleFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); Blur(Bmp); DrawRadix(math.random(0,BmpWidth(Bmp)),0,Radix); DisplayBitmap(Bmp,Wnd); end

    Webcam diff demo

    Uses webcam images to display a differential video: pixels that doesn't change over time are dark, the ones that changes tends to be bright... and the whole tends to be rather hypnotic to watch :-)

    Dislay the source code...

      Alert("Please note this demo needs a webcam to operate properly"); Wnd=OpenWindow(320,240,"Webcam"); Bmp=CreateBitmap(320,240); GrabBmp=CaptureImage(); while (1==1) do RefBmp =GrabBmp; GrabBmp=CaptureImage(); Ink(0,0,0); Opacity(10); RectFill(Bmp,0,0,320,240); Opacity(255); DiffBmp=WhatChanged(RefBmp,GrabBmp,1,2010); Tint(DiffBmp,50,100,200); Bleach(Bmp,0,0,DiffBmp); DestroyBitmap(DiffBmp); DisplayBitmap(Bmp,Wnd); DestroyBitmap(RefBmp); end

    Flight

    Not so long ago, my friend François Lamotte sent me an email about an outstanding computer artist: Robert Hodgin ("flight404").

    Some of his work can be seen here: www.vimeo.com/flight404, and of course I spent an evening watching at all the videos, and watching again, and again the next days :-).

    It was breathtaking: His last work (Solar) was the crossbreed between some kind of exploding star and an amoeba and the whole... mindblowingly beautifull!

    And all this was animated and computer generated using... Oh my God ! Processing !!! So, of course I begun to wonder if such a thing was possible to make in Lew and fear it wasn't ! The only way to know for sure was to try. This is the result of this attempt. Of course it's only worth an afternoon of work and it lacks the talent of Mr Robert Hodgin, but still proves that "Lew could do it" :-)

    Various versions of the flight demo can be downloaded together with the Lew interpreter here: flights.zip... it's less than 200Kb big :-)

    Dislay the source code...

      -- Graphic concept based on the work "Solar" of flight404 (Robert Hodgin) Bmp=CreateBitmap(640,480); Wnd=OpenWindow(BmpWidth(Bmp),BmpHeight(Bmp),"Flight"); Ink(0,0,0); Opacity(255,"M"); RectangleFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); -- Start with a random distribution of particles Gravity ={x=0,y=0,z=0}; Attractor ={x=0,y=0,z=0,coef=1,r=80}; Repulsion ={coef=-0.05}; Amort =0.95; DoLine =1; DoAureole =1; DoSmoke =1; DoBall =1; ExplodeProb=1/500; ParticleQtt=300; PartPad =10; Particle={}; for i=0,ParticleQtt,1 do Particle[i]={ x =math.random(300); y =0; z =math.random(300); vx=(math.random(1000)-500)/250; vy=(math.random(1000)-500)/250; vz=(math.random(1000)-500)/250; ax=0; ay=0; az=0; r=1; }; end -- Prepare particles images of various sizes ParticleImage={}; for ParticleSize=1,100,1 do Image=CreateBitmap(ParticleSize+5,ParticleSize+5); Ink(0,0,0); Opacity(255,"M"); RectangleFill(Image,0,0,BmpWidth(Image),BmpHeight(Image)); Opacity(10,"B"); for i=0,300,3+(100-ParticleSize)/20 do r,g,b=HsvToRgb(ParticleSize/100*255,150,127+(1-i/300)*127); Ink(r,g,b); CircleFill(Image,BmpWidth(Image)/2,BmpHeight(Image)/2,i/300*ParticleSize/2); end ParticleImage[ParticleSize]=Image; end -- Prepare corona image CoronaImage=CreateBitmap(Attractor.r*2,Attractor.r*2); Ink(0,0,0); Opacity(255,"M"); RectangleFill(CoronaImage,0,0,BmpWidth(CoronaImage),BmpHeight(CoronaImage)); Opacity(10,"B"); for ParticleSize=1,100,1 do r=math.random(Attractor.r-6); if (r>100) then r=100; end x=math.random(BmpWidth (CoronaImage)-BmpWidth (ParticleImage[r])); y=math.random(BmpHeight(CoronaImage)-BmpHeight(ParticleImage[r])); Bleach(CoronaImage,x,y,ParticleImage[r]); end -- Move particles one step function MoveParticles() local i,rx,ry,rz,r,rrr,c,j,k; for i=0,ParticleQtt,1 do -- gravity Particle[i].ax=Gravity.x; Particle[i].ay=Gravity.y; Particle[i].az=Gravity.z; -- attraction rx=(Attractor.x-Particle[i].x); ry=(Attractor.y-Particle[i].y); rz=(Attractor.z-Particle[i].z); r=math.sqrt(rx*rx+ry*ry+rz*rz); c=(r-Attractor.r)/100; rrr=r*r*r; Particle[i].ax=Particle[i].ax+c*Attractor.coef*rx/r; Particle[i].ay=Particle[i].ay+c*Attractor.coef*ry/r; Particle[i].az=Particle[i].az+c*Attractor.coef*rz/r; -- repulsion between particles for j=0,5,1 do k=math.random(ParticleQtt); if (not(k==i)) then rx=(Particle[k].x-Particle[i].x); ry=(Particle[k].y-Particle[i].y); rz=(Particle[k].z-Particle[i].z); r=math.sqrt(rx*rx+ry*ry+rz*rz); if (Particle[i].r>r) then Particle[k].r=r end if (Particle[k].r>r) then Particle[i].r=r end Particle[i].ax=Particle[i].ax+Repulsion.coef*rx/r; Particle[i].ay=Particle[i].ay+Repulsion.coef*ry/r; Particle[i].az=Particle[i].az+Repulsion.coef*rz/r; end end Particle[i].vx=(Particle[i].vx+Particle[i].ax)*Amort; Particle[i].vy=(Particle[i].vy+Particle[i].ay)*Amort; Particle[i].vz=(Particle[i].vz+Particle[i].az)*Amort; Particle[i].x =Particle[i].x+Particle[i].vx; Particle[i].y =Particle[i].y+Particle[i].vy; Particle[i].z =Particle[i].z+Particle[i].vz; if (Particle[i].x<0 ) then Particle[i].x=0 end if (Particle[i].x>BmpWidth (Bmp)) then Particle[i].x=BmpWidth(Bmp) end if (Particle[i].z<0 ) then Particle[i].z=0 end if (Particle[i].z>BmpHeight(Bmp)) then Particle[i].z=BmpHeight(Bmp) end if (math.random(10000)>10000*(1-ExplodeProb)) then Particle[i].r=math.random(100); else Particle[i].r=Particle[i].r/1.2; rx=(Particle[k].vx); ry=(Particle[k].vy); rz=(Particle[k].vz); r=math.sqrt(rx*rx+ry*ry+rz*rz)*3; if (r>100) then r=100 end if (Particle[i].r<r) then Particle[i].r=r end end end end -- Display Particles function DisplayParticle(i) local size; local Pad=PartPad; local Frontpad=20; local rx,ry,rz; local opa; if ((Particle[i].r>3) and (DoAureole==1)) then opa=10+Particle[i].r/10; if (opa>20) then opa=20; end Opacity(opa,"B"); Ink(250,100,100); CircleFill(Bmp,Particle[i].x,Particle[i].z,Particle[i].r*1.0+5); opa=20+Particle[i].r/3; if (opa>50) then opa=50; end Opacity(opa,"B"); Ink(250,200,150); Circle(Bmp,Particle[i].x,Particle[i].z,Particle[i].r*1.0+5); end Opacity(255); size=math.floor(Particle[i].r); if (size<=0) then size=1 end Bleach(Bmp,Particle[i].x-BmpWidth(ParticleImage[size])/2,Particle[i].z-BmpWidth(ParticleImage[size])/2,ParticleImage[size]); if (DoLine==1) then rx=(Attractor.x-Particle[i].x); ry=(Attractor.y-Particle[i].y); rz=(Attractor.z-Particle[i].z); r=math.sqrt(rx*rx+ry*ry+rz*rz); Opacity(10,"B"); Thickness(3); Ink(120,120,120); Line(Bmp,Particle[i].x,Particle[i].z,Particle[i].x-rx/r*50 ,Particle[i].z-rz/r*50 ); Opacity(10,"B"); Thickness(2); Ink(120,120,120); Line(Bmp,Particle[i].x,Particle[i].z,Particle[i].x-rx/r*100,Particle[i].z-rz/r*100); Opacity(10,"B"); Thickness(1); Ink(120,120,120); Line(Bmp,Particle[i].x,Particle[i].z,Particle[i].x-rx/r*400,Particle[i].z-rz/r*400); end ry=math.sqrt(Particle[i].y*Particle[i].y); if ((ry<Pad) and (DoSmoke==1)) then Opacity(math.floor((Pad-ry)/Pad*90)); Bleach(Bmp,Particle[i].x-BmpWidth(CoronaImage)/2,Particle[i].z-BmpWidth(CoronaImage)/2,CoronaImage); end end function DisplayParticles() local i; local size; local Backpad=20; local Frontpad=20; local rx,ry,rz; for i=0,ParticleQtt,1 do if (Particle[i].y>=0) then DisplayParticle(i); end end if (DoBall==1) then if (not (DoSmoke==1)) then Opacity(20,"B"); Ink(255,100,100); CircleFill(Bmp,Attractor.x,Attractor.z,Attractor.r+20); Opacity(40,"B"); Ink(255,255,255); Circle(Bmp,Attractor.x,Attractor.z,Attractor.r+20); end Opacity(255,"M"); Ink(0,0,0); CircleFill(Bmp,Attractor.x,Attractor.z,Attractor.r); if (not (DoSmoke==1)) then Opacity(20,"B"); Ink(255,100,100); CircleFill(Bmp,Attractor.x,Attractor.z,Attractor.r+20); end end for i=0,ParticleQtt,1 do if (Particle[i].y<0) then DisplayParticle(i); end end end -- Go animate for i=1,100,1 do Attractor.x,Attractor.z,Button=Mouse(Wnd); MoveParticles(); end while (1==1) do Attractor.x,Attractor.z,Button=Mouse(Wnd); if (Button==1) then Amort=0.99 else Amort=0.95 end MoveParticles(); Ink(0,0,0); Opacity(255,"M"); RectangleFill(Bmp,0,0,BmpWidth(Bmp),BmpHeight(Bmp)); DisplayParticles(); DisplayBitmap(Bmp,Wnd); end
end -- of Gallery