Drawing Ribbons in Fluxus

Playing with drawing ribbons in Fluxus (part of my mater plan to port all of my live-drawing software to Fluxus).
(This code is about 70% taken from Dave Griffith‘s L-Systems drawing code – thanks Dave!)

Ribbon Drawing in Fluxus

(clear)

(texture (load-texture "test.png"))

;----- return a vector on a circle based on index

(define (calc-xyz index max-index r)
(let*
( [angle (* 6.28312 (/ index (- max-index 1)))]
[x (* (cos angle) r)]
[y (* (sin angle) r)] )

;(display (vector x y 0))(newline)
(vector x y 0))
)

(define (build-ellipse rmin rmaj num-verts)
(define p (build-polygons (* 3 num-verts) 'triangle-list))
(with-primitive p
(for ([i (in-range 0 (* 3 num-verts) 3) ])
(pdata-set! "p" i (vector 0 0 0))
(pdata-set! "n" i (vector 0 0 -1))
(pdata-set! "p" (+ i 1) (calc-xyz (/ i 3) num-verts rmin))
(pdata-set! "n" (+ i 1) (vector 0 0 -1))
(pdata-set! "p" (+ i 2) (calc-xyz (+ (/ i 3) 1) num-verts rmin))
(pdata-set! "n" (+ i 2) (vector 0 0 -1)))
(poly-convert-to-indexed)
)
p)

; gets a line representing a segment of the projection of the mouse into 3D space
; should move this into the fluxus scheme library
(define (get-line-from-mouse)
(let* ((ndcpos (vector (* (- (/ (mouse-x) (vx (get-screen-size))) 0.5) 2)
(* (- (- (/ (mouse-y) (vy (get-screen-size))) 0.5)) 1.5) -1))
(scrpos2 (vtransform (vmul ndcpos 50) (minverse (get-camera-transform))))
(scrpos (vtransform ndcpos (minverse (get-camera-transform)))))
(list scrpos scrpos2)))

; we'll just use the end of the projection line here
(define (mouse-pos)
(cadr (get-line-from-mouse)))

; converts a 2D vector into an angle, with some dodgy dave maths
(define (2dvec->angle x y)
(let ((q (/ 3.141 2)))
(when (zero? y) (set! y 0.0001))
(cond
((>= y 0)
(fmod (* (+ q q q (- q (atan (/ x y)))) 57.2957795) 360))
(else
(fmod (* (+ q (- q (atan (/ x y)))) 57.2957795) 360)))))

;------------------------------------------------------
; strokes are collections of points representing mouse movement

(define-struct stroke (points ribb) #:mutable)

(define (build-stroke)
(make-stroke (list (vector 0 0 -40)) (build-ribbon 2)))
; start with a point in the middle of the screen

(define (stroke-clear stroke)
(set-stroke-points! stroke (list (vector 0 0 -40)))
(set-stroke-ribb! (build-ribbon 2)))

(define (stroke-add stroke pos)
(set-stroke-points! stroke (cons pos (stroke-points stroke))))

(define (stroke-last-point stroke)
(car (stroke-points stroke)))

(define (stroke-update stroke)
(destroy (stroke-ribb stroke))

(set-stroke-ribb! stroke
(build-ribbon (length (stroke-points stroke))))

; make a new point when the mouse is suitibly far from the last point
(when (> (vdist (stroke-last-point stroke) (mouse-pos)) 2)
(stroke-add stroke (mouse-pos)))

(with-primitive (stroke-ribb stroke)
(pdata-map! (lambda (w) 1.5) "w")
(pdata-index-map!
(lambda (n p)
(list-ref (stroke-points stroke) n))
"p"))
)

; draw some blobs to indicate the path drawn
;(define (stroke-render stroke))

(define mp
(with-state
(colour (vector 1 1 1))
(build-ellipse 1 1 12)))

;------------------------------------------------------

; a fluxus mouse pointer!
(define (draw-mouse)
(with-primitive mp
(identity)
(colour (vector 1 1 0))
(translate (mouse-pos))
(hint-unlit)
))

(define stroke (build-stroke))
(define root (build-locator))
(define debounce #t)

(define (breathe stroke)
(with-primitive (stroke-ribb stroke)
(pdata-map! (lambda (w) 1.5) "w")
(pdata-index-map!
(lambda (n w)
(+ 1.2 (sin (time))))
"w"))
)

(define (animate)
(draw-mouse)
(when (mouse-button 1)
(stroke-update stroke))

(breathe stroke)

)

(set-camera-transform (mtranslate (vector 0 0 -10)))
(light-diffuse 0 (vector 0 0 0))
(define l (make-light 'point 'free))
(light-diffuse l (vector 1 1 1))
(light-position l (vector -50 50 0))

(every-frame (animate))