alexis%yummy@GATEWAY.MITRE.ORG (06/28/89)
Yet another remake/tweek of the psPyro program, making it more worthy of a workstation (read as "it sucks us cpu cycles"). This version has lots of colors, more interesting explosions, more than one firecracker in the air at once (I have it set to 3, but it's just a variable), and general tweeking (they fly faster, explode slower, etc). This just assumes you're running on a color machine. alexis wieland alexis%yummy@gateway.mitre.org --------------------------- cut here ---------------------- #! /usr/NeWS/bin/psh % % psPyro, a user extensible fireworks display screen saver. % % % Physical screen dimensions ------------------------------------------ % /screen_width 0 def /screen_height 0 def % % Heuristics for firework creation and display (user configurable) ---- % /unusable_screen_width 0.1 def % set to percent of physical screen width /unusable_screen_height 0.1 def % set to percent of physical screen height /minimum_trail_height 0.75 def % set to percent of physical screen height /minimum_explosion_angle 100 def /maximum_explosion_angle 150 def /minimum_#_explosions 2 def /maximum_#_explosions 6 def /trail_length 5 def % the length of the firework trail /n-in-air-at-once 3 def % number of fireworks at any time /multiple_explosion_radius 100 def % radius of multiple explosions from original % array of colors /colortable [ 1 1 1 rgbcolor 1 0 0 rgbcolor 0 1 0 rgbcolor 0 0 1 rgbcolor 1 1 0 rgbcolor 0 1 1 rgbcolor 1 .5 0 rgbcolor 1 0 .5 rgbcolor .8 .5 .2 rgbcolor .92 .68 .92 rgbcolor .86 .44 .86 rgbcolor ] def % randomly set color /randcolor { colortable random colortable length 1 sub mul floor get setcolor } def % % Firework explosion definitions % % array to keep the names of the different explosions in /explosion_kinds [ /dots_explosion /circle_explosion /star_explosion /colored_circle_explosion ] def % % Dots explosion. /draw_one_quarter { 30 0 moveto 2 -2 rlineto 2 2 rlineto -2 2 rlineto closepath fill 20 10 3 3 rectpath fill 10 20 3 3 rectpath fill } def /dots_explosion { % x y => - gsave translate 360 random mul rotate 8 random mul cvi 2 add .5 random add dup scale gsave 5 { randcolor dup { draw_one_quarter 360 1 index div rotate } repeat 1.3 1.3 scale big_delay } repeat grestore gsave 5 { 0 setgray dup { draw_one_quarter 360 1 index div rotate } repeat 1.3 1.3 scale big_delay } repeat pop grestore grestore } def % dots_explosion % % Circle explosion. % /draw_circle { % - => - 0 0 10 0 360 arc stroke } def /circle_explosion { % x y => - gsave translate .5 random add dup scale gsave 6 { 1.4 dup scale randcolor big_delay draw_circle } repeat grestore gsave 6 { 1.4 dup scale 0 setgray big_delay draw_circle } repeat grestore grestore } def % % Star explosion. % /draw_star { % n-lines => n-lines gsave dup { -30 0 moveto 60 0 rlineto stroke 360 1 index div rotate } repeat grestore } def /star_explosion { % x y => - gsave translate .5 random add dup scale 360 random mul rotate 10 random mul 4 add gsave 4 { 1.4 dup scale randcolor big_delay draw_star } repeat grestore gsave 4 { 1.4 dup scale 0 setgray big_delay draw_star } repeat grestore pop grestore } def % % Colored circle explosion. % /draw_dot { % - => - 0 0 10 0 360 arc fill } def /colored_circle_explosion { % x y => - gsave translate .5 random add dup scale gsave 10 { 1.2 dup scale randcolor big_delay draw_dot } repeat 0 setgray big_delay big_delay draw_dot grestore grestore } def % % Support utilities --------------------------------------------------- % % % Delay loops. % /big_delay { 1 2048 div sleep } def % % Draw one instance of a firework trail from: % angle to angle % theta theta + trail_length - 1 % /draw_trail { % theta => - /theta exch def % erase the first degree from the previous trail 0 setgray 0 0 1 theta 1 sub theta newpath arc stroke 1 setgray theta 1 theta trail_length add 1 sub { 0 0 1 4 -1 roll dup 1 add newpath arc stroke } for } def % % Animate the entire firework trail up until the explosion. % /animate_trail { % - => - % draw the first trail instance 1 setgray 0 1 trail_length 1 sub { 0 0 1 4 -1 roll dup 1 add newpath arc stroke } for % draw the rest of the trail 1 1 explosion_angle { draw_trail pause } for % remove the last trail instance 0 setgray explosion_angle 1 explosion_angle trail_length add 1 sub { 0 0 1 4 -1 roll dup 1 add newpath arc stroke } for } def % % Determine the characterictics of the next firework. % /determine_firework_characteristics { % - => - % randomly pick the starting position to fire the firework from /trail_start_x screen_width random mul store % % pick the direction of the firework trail % % if the picked starting position is too close to a screen % edge, force the direction to be towards the opposite screen % side, otherwise randomly pick the direction % trail_start_x unusable_screen_width le { /trail_going_left? false store } { trail_start_x screen_width unusable_screen_width sub ge { /trail_going_left? true store } { % randomly pick the direction /trail_going_left? random round 0 eq store } ifelse } ifelse % randomly pick the width of the firework trail trail_going_left? { /trail_width trail_start_x random mul store } { /trail_width screen_width trail_start_x sub random mul store } ifelse % randomly pick the height of the firework trail /trail_height screen_height random mul store trail_height minimum_trail_height le { /trail_height minimum_trail_height store } if % randomly pick the ending angle of the firework explosion /explosion_angle maximum_explosion_angle minimum_explosion_angle sub random mul minimum_explosion_angle add round store } def % % Animate a firework explosion. % /animate_explosion { % explosion_x explosion_y #explosions => - /#explosions exch store /explosion_y exch store /explosion_x exch store % randomly pick which explosion to use /which_explosion explosion_kinds explosion_kinds length random mul floor get def % explode the first of the explosions explosion_x explosion_y which_explosion cvx exec % explode the remaining number of explosions (possible none), % randomly picking each location based upon the initial explosion % location #explosions 1 sub { % randomly pick another explosion location 360 random mul dup cos multiple_explosion_radius mul explosion_x add exch sin multiple_explosion_radius mul explosion_y add which_explosion cvx exec } repeat } def /do-it { gsave /trail_width 0 def /trail_height 0 def /trail_start_x 0 def /trail_going_left? true def /explosion_angle 0 def /#explosions null store /explosion_y null store /explosion_x null store /which_explosion null store initmatrix sky setcanvas % create a new firework determine_firework_characteristics % translate to the center of the firework trail arc trail_start_x unusable_screen_width add trail_width 2 div trail_going_left? { sub } { add } ifelse 0 translate trail_going_left? not { -1 1 scale } if % create the firing of the firework randcolor trail_width 2 div 0 20 0 180 arc fill 3 { big_delay } repeat 0 setgray trail_width 2 div 0 20 0 180 arc fill % create the firework trail trail_width 2 div trail_height scale animate_trail % calculate the location of the firework explosion initmatrix trail_start_x unusable_screen_width add trail_width 2 div trail_going_left? { sub } { add } ifelse explosion_angle trail_length add cos trail_width 2 div mul trail_going_left? { add } { sub } ifelse explosion_angle trail_length add sin trail_height mul % calculate the number of explosions for the firework maximum_#_explosions random mul round minimum_#_explosions max % create the explosion! animate_explosion grestore } def % % Continually make fireworks. % /make_fireworks { % - => - { n-in-air-at-once { { 32 dict begin { do-it } loop end } fork } repeat } fork } def % % Main ---------------------------------------------------------- % % get the dimensions of the physical screen clippath pathbbox /screen_height exch def /screen_width exch def clear % calculate the actual values of the firework creation and display heuristics /unusable_screen_width screen_width unusable_screen_width mul def /unusable_screen_height screen_height unusable_screen_height mul def /minimum_trail_height screen_height minimum_trail_height mul def % calculate the usable screen area /screen_height screen_height unusable_screen_height sub def /screen_width screen_width unusable_screen_width dup add sub def % create the black sky clippath pathbbox rectpath /sky framebuffer newcanvas def sky reshapecanvas sky /Mapped true put sky setcanvas 0 fillcanvas % remove the cursor /nouse /nouse_m sky setstandardcursor % start the fireworks display make_fireworks % wait for a mouse movement or click to end the fireworks display createevent dup begin /Name [ /LeftMouseButton /MiddleMouseButton /RightMouseButton /MouseDragged ] def /Canvas sky def end expressinterest awaitevent currentprocess killprocessgroup