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

;;

;; Pixelate video into 32*32 grid

;;

;; Create a pixellated image and transfer the pixel colours

;; to an identical number of vector paths.  Then draw the vector

;; paths over the top of the original image.

;;

;; Move the vector paths by a small amount each animation frame.

;;

;; Note that the vector paths and the back ground image are 

;; opposites.

;;

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


(gfx:start-live-video)


(define row-length 32) ; number of squares to animate 

(define nodes (* row-length row-length))

(define size 20) ; square size 


; set up graphics including vectors for paths, points, colours, styes etc.

(define canvas (gfx:make-canvas (* size row-length) (* size row-length)))

(gfx:clear-canvas (now) canvas '(0 0 0 1)) ; black background 


; setup paths at random coordinates between 100,100 and 200,200

(define paths (make-vector-with-proc nodes

                                     (lambda (i)

                                        (gfx:make-square (* size (floor (/ (- nodes i 1) row-length)))

                                                         (* size (fmod (- nodes i 1) row-length))                       

                                                         size))))


;; styles 

(define styles (make-vector nodes *gfx:fill-path*))

;; strokes to 0

(define strokes (make-vector nodes 0))

;; widths to 0

(define widths (make-vector nodes 1))

;; x,y coordinates to retrieve pixels from image

(define idxs (make-vector (* 1024 2)))


;; setup x,y coordinates

(dotimes (i 1024)

   (let ((k (* i 2)))

      (vector-set! idxs k (real->integer (/ i row-length)))

      (vector-set! idxs (+ k 1) (fmod i row-length))))            


;; vectors for holding random x and y coordinates

(define randx (make-vector 1024 0))

(define randy (make-vector 1024 0))


;; animate movie

;; 

;; 1) get image from camera

;; 2) pixellate image (i.e. compress from full size down to 32*32)

;; 3) choose random numbers between -0.5 ... 0.5 for amount to move paths by (x and y)

;; 4) move paths by x and y amounts

;; 5) draw camera image onto the background (scaling from 640*480 to 640*640)

;; 6) draw paths onto the background image (over the top of the camera image)

;; 7) draw background to the canvas

;;

;; Try replacing the second image2image expression with (clear-image background-image '(0 0 0 1))

(define animate

   (lambda (time pixel-image background-image)

      (let* ((frame (gfx:get-live-frame))

            (camera-image (gfx:convert-image frame)))

         (gfx:image2image camera-image pixel-image 1.0 (list 0 0 row-length row-length) '(0 0 640 480))

         (math:vector-rand randx) ;; generate 1024 random numbers         

         (math:vector-rand randy) ;; generate 1024 random numbers

         (math:vector- randx .5) ;; change range from 0 ... 1 to -0.5 ... 0.5

         (math:vector- randy .5) ;; change range from 0 ... 1 to -0.5 ... 0.5

         (gfx:move-group time paths randx randy) ;; move 1024 paths by randx randy

         (gfx:image2image camera-image background-image 1.0 

                      (list 0 0 (* row-length size) (* row-length size)) '(0 0 640 480)) ;; draw camera image onto background       

         (gfx:group2image background-image paths strokes 

                      (gfx:get-image-pixels pixel-image idxs) widths styles) ;; draw all paths onto background

         (gfx:draw-image time canvas background-image 1) ;; draw background to canvas

         (objc:release (+ time 3000) frame camera-image)

         (callback (+ time 3000) 'animate (+ time 5000) pixel-image background-image))))


;; call animage and create background and pixel images 

;; to be resused (i.e. we don't want to re-create them in each animation frame)

;;

(animate (now)  

         (gfx:make-image row-length row-length)

         (gfx:make-image (* row-length size) (* row-length size)))