Particle Systems Example

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  This code is based on an
;;  example written by Steve May.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define *gravity* (vec3 0 -0.98 0))
(define *damping* 1)
(define render-rib? #f)
(define *particles* '())    ;; list of live particles
(define (add-particle particle) (set! *particles* (cons particle *particles*)))
(define *num-particles* 2)
(define (randR low high) (+ (* (rand) (- high low)) low))

; 15 fps
(define *dt* 0.2)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (particle-create)
  
  (let (
	(mass 1)
	(velocity (vec3 0 0 1))
	(position (vec3 0 0 0))
	(acceleration (vec3 0 0 0))
	(dead? #f)
	)
    
    (define (set-velocity! vel) (set! velocity vel))
    (define (set-position! pos) (set! position pos))
    (define (set-dead! dead) (set! dead? dead))
    
    (define (update)
      (let ((p-list *particles*)
	    (force (vec3 0 0 0))
	    )
	
	;; compute external forces
	(set! force (* mass *gravity*))
	
	;; compute new velocity
	(set! acceleration (/ force mass))
	(set! velocity (+ velocity (* acceleration *dt*)))
	
	;; dampen
	(set! velocity (* velocity *damping*))
	
	;; compute new position
	(set! position (+ position (* velocity *dt*) 
			  (* 0.5 *gravity* *dt* *dt*)))
	
	;; determine if dead
	
	(if (< (ycomp position) -10) (set! dead? #t))
	))

    (define (draw) 
      (separator (translate position) (sphere)))
      
    (lambda (message)
      (cond
       ((eq? message 'set-velocity!) set-velocity!)
       ((eq? message 'set-position!) set-position!)
       ((eq? message 'set-dead!) set-dead!)
       ((eq? message 'velocity) velocity)
       ((eq? message 'position) position)
       ((eq? message 'dead?) dead?)
       ((eq? message 'update) (update))
       ((eq? message 'draw) (draw))
       (else (error "particle: invalid operation" message))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (generate-particles)
  (let (
	(n *num-particles*)
	(particle ())
	)
    (while (> n 0)
	   (begin
	     (set! particle (particle-create))
	     ((particle 'set-velocity!)
		     (vec3 (randR -1 1) (randR 9 11) (randR -1 1)))
	     ((particle 'set-position!) (vec3 0 0 0))
	     
	     (add-particle particle)
	     (set! n (sub1 n))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (update-particles)
  (define p-list *particles*)
  (while (not (null? p-list))
    (begin
      ((car p-list) 'update)
      (set! p-list (cdr p-list)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (draw-particles)
  (define p-list *particles*)
  (while (not (null? p-list))
    (begin
      ((car p-list) 'draw)
      (set! p-list (cdr p-list)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (remove-dead-particles)

  (define (helper p-list)
    (if (null? p-list) 
	p-list
	(if ((car p-list) 'dead?) 
	    (helper (cdr p-list))
	    (cons (car p-list) (helper (cdr p-list))))))

  (set! *particles* (helper *particles*)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (animate duration)
  (begin 
    (set-time! 0)
    (while (< time duration)
      (begin
	(print time)
	(generate-particles)
	(update-particles)
	(remove-dead-particles)
	(world
	 (camera "main" "perspective" 'from (vec3 59 28 85) 
		 'to (vec3 0 30 0) 'fov 45)
	 (divisions 3 3)
	 (color .7 .2 0)
	 (draw-particles)
	 )

	(if render-rib? 
	    (render 
	     'display-name "frame.~s"
	     'format '(160 121 1)
	     ))
	
	(set-time! (+ time 1))
	))))
  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(animate 120)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



Return to Particle Systems
mrl