(define num-plants 1000)

(define-struct plant (root shape widths (start-time #:mutable) (started #:mutable)))

(define (choose l)
    (list-ref l (random (length l))))

(define (build-plant size)
    (make-plant
        (with-state 
            (translate (vector 1000 0 0))
            ;(shader "simple.vert.glsl" "simple.frag.glsl")
            ;(hint-none)
            ;(hint-wire)
            (hint-unlit)
            ;            (hint-ignore-depth)
            (build-ribbon size))
        (let ((r (* 50 (crndf)))
                (d (vmul (vector 0 0.5 0.2) (* (rndf) 1)))
                (p (vector 0 0 0))
                (w (* 5 (rndf)))
                (off (crndf)))
            (build-list size 
                (lambda (i) 
                    (set! p (vadd p d))
                    (set! d (vtransform d (mrotate (vector 0 0 (* r (+ off (* 1 (sin (* i w)))))))))
                    (set! d (vmul d 0.9))
                    p)))
        (build-list size
            (lambda (i)
                (let ((t (/ i size)))
                    (* 1 t t (* 0.3 (+ 1 (cos (* t 3.141))))))))
        (time)
        #f))

(define (reset-plant plant pos col tex)
    (with-primitive (plant-root plant)
        (identity)
        (colour col)
        (texture (load-texture tex))       
        ;(shader-set! (list "ColourMap" 0))
        (translate pos)
        (pdata-map!
            (lambda (p)
                (vector 0 0 0))
            "p")
        (pdata-index-map!
            (lambda (i w)
                (list-ref (plant-widths plant) i))
            "w"))
    (set-plant-start-time! plant (time))
    (set-plant-started! plant #t))

(define (plant-update plant)
    (let ((t (* (- (time) (plant-start-time plant)) 2.5)))
        (with-primitive (plant-root plant)
            ;(shader-set! (list "Time" (* 10 (time))))
            
            (when (< t (pdata-size))
                (pdata-index-map!
                    (lambda (i p)
                        (let ((t (- t i)))
                            (if (> t 0) 
                                (vmix p (list-ref (plant-shape plant) (inexact->exact (floor t))) 0.9)
                                p)))
                    "p")))))


(define (plant-destroy plant)
    (destroy (plant-root plant)))

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(define (random-pos i)
    (let* ((t (* (random (inexact->exact (floor (/ (length i) 3)))) 3))
            (b (rndbary)))
        (vadd 
            (vmul (pdata-ref "p" (list-ref i t)) (vx b))
            (vmul (pdata-ref "p" (list-ref i (+ t 1))) (vy b))
            (vmul (pdata-ref "p" (list-ref i (+ t 2))) (vz b)))))


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(define (setup-flowers flowers)
    (with-primitive flowers
        (translate (vector 0 0 0.1))
        (hint-depth-sort)
        (pdata-add "plant" "f")
        (pdata-add "vert" "f")
        (pdata-add "max-size" "f")
        (pdata-map!
            (lambda (c)
                (vector (+ 0.5 (* 0.5 (rndf))) (* 0.5 (rndf)) (rndf)))
            "c")
        (pdata-map!
            (lambda (c)
                (vector 0 0 0))
            "s")
        (pdata-map!
            (lambda (c)
                (* (rndf) 0.6))               
            "max-size")))

(define (update-flowers flowers plants)
    (with-primitive flowers
        (pdata-map!
            (lambda (p plant vert)
                (if (zero? vert)
                    p
                    (with-primitive (plant-root (list-ref plants (inexact->exact plant)))
                        (vtransform (pdata-ref "p" (inexact->exact vert)) (get-transform)))))
            "p" "plant" "vert")
        (pdata-map!
            (lambda (s max-size)
                (if (or (> (vx s) max-size) (< (vx s) 0.005)) 
                    s (vadd s (vector 0.001 0.001 0.001))))
            "s" "max-size")
        (when (zero? (random 10))
            (let ((f (random (pdata-size))))
                (when (zero? (vx (pdata-ref "s" f)))
                    (let* ((plant-num (random (length plants)))
                            (plant (list-ref plants plant-num)))
                        (when (plant-started plant)
                            (pdata-set! "plant" f (random (length plants)))
                            (pdata-set! "vert" f (+ 5 (random 10)))
                            (pdata-set! "s" f (vector 0.01 0.01 0.01))
                            (pdata-set! "p" f (vector 1000 0 0)))))))))

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(clear)

(light-diffuse 0 (vector 0 0 0))
(let ((l (make-light 'point 'free)))
    (light-diffuse 1 (vector 1 1 1))
    (light-position l (vector 0 100 100)))

(define bg (with-state
        (translate (vector 0 3 -6))
        (rotate (vector 0 180 0))
        (hint-wire)
        (wire-colour (vector 0 0 1))
        (colour (vector 0 0 0.5))
        (load-primitive "meshes/k.obj")))

(with-primitive bg (hide 1))

(define shape (load-primitive "meshes/proc3.obj"))

(define flowers (with-state
        (hint-unlit)
        (texture (load-texture "textures/flower2.png"))
        (build-particles 400)))

(setup-flowers flowers)

(define plants (build-list num-plants
        (lambda (_) 
            (build-plant 20            
                ))))

(define cur 0)


(define i (with-primitive shape 
        (hint-wire)
        (hint-unlit)
        (colour 0.2)
        (wire-colour 0.5)
        (backfacecull 0)
        (translate (vector 0 3 -6))
        (rotate (vector 0 180 0))
        (scale 10)
        (hide 1)
        (apply-transform)
        ;(poly-convert-to-indexed)
        (poly-indices)))

(define (plants-cons plants pos col tex)
    (reset-plant (list-ref plants cur) pos col tex)
    (set! cur (modulo (+ cur 1) (length plants))))

(define (plants-update)
    (when (key-pressed "b")
        (with-primitive bg (hide 0)))
    (when (key-pressed "c")
        (with-primitive bg (hide 1)))
    
    
    (when (zero? (random 50))
        (with-primitive shape
            (let ((p (random-pos i)))
                (when (not (and (zero? (vx p))))
                    (let ((col (vector (* 0.75 (rndf)) 1 (* 0.75 (rndf))))
                            (tex (choose (list
                                        "textures/leaf-01.png"
                                        "textures/leaf-02.png"
                                        "textures/leaf-03.png"))))
                        
                        (for ((i (in-range 0 6)))
                            (plants-cons plants p col tex)))))))
    (for-each
        (lambda (plant)
            (plant-update plant))
        plants)
    (update-flowers flowers plants))

(show-axis 0)

(every-frame (plants-update))


