groworld/hayfever/hayfever.scm

566 lines
21 KiB
Scheme
Raw Normal View History

2009-03-12 10:45:34 +00:00
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(require scheme/class)
(require mzlib/string)
(osc-destination "osc.udp://127.0.0.255:4001")
(osc-source "4002")
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; pixel primitive things for getting connection points
; 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)))))
(define (i->pos i)
(vector (modulo i (pixels-width))
(quotient i (pixels-width)) 0))
(define (pos->i pos)
(+ (* (round (vy pos)) (pixels-width)) (round (vx pos))))
(define (pixels-ref name pos)
(pdata-ref name (pos->i pos)))
(define (pixels-set! name pos s)
(pdata-set! name (pos->i pos) s))
(define (search i)
(cond
((eq? i (pdata-size)) i)
((< (vr (pdata-ref "c" i)) 0.5) i)
(else (search (+ i 1)))))
(define (flood pos tc av)
(define (rec-flood pos)
(pixels-set! "c" pos (vector 1 0 1))
(set! tc (+ tc 1))
(set! av (vadd av pos))
(when (< (vr (pixels-ref "c" (vadd pos (vector -1 0 0)))) 0.5)
(rec-flood (vadd pos (vector -1 0 0))))
(when (< (vr (pixels-ref "c" (vadd pos (vector 1 0 0)))) 0.5)
(rec-flood (vadd pos (vector 1 0 0))))
(when (< (vr (pixels-ref "c" (vadd pos (vector 0 1 0)))) 0.5)
(rec-flood (vadd pos (vector 0 1 0))))
(when (< (vr (pixels-ref "c" (vadd pos (vector 0 -1 0)))) 0.5)
(rec-flood (vadd pos (vector 0 -1 0)))))
(rec-flood pos)
(vmul av (/ 1 tc)))
(define (find-centroids pos l)
(let ((i (search pos)))
(cond ((eq? i (pdata-size)) l)
(else
(find-centroids i
(cons (flood (i->pos i) 0 (vector 0 0 0)) l))))))
(define (convert-to-pos l)
(map
(lambda (cp)
(vector (- (- (/ (vx cp) (pixels-width)) 0.5))
(- 1 (/ (vy cp) (pixels-height))) 0))
l))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; a cache for the connection points - should save this out
(define connection-cache '())
(define (get-connection-list id)
(let ((ret (assoc id connection-cache)))
(cond
(ret (cdr ret))
(else
(let* ((tex (load-primitive (string-append "textures/comp-cp-" id ".png")))
(connections (with-primitive tex (convert-to-pos (find-centroids 0 '())))))
(set! connection-cache (cons (cons id connections) connection-cache))
(destroy tex)
connections)))))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; a plant component
(define-struct component (root (col #:mutable) children))
2009-03-12 10:45:34 +00:00
(define (build-component id col children)
2009-03-12 10:45:34 +00:00
(cond
((null? children)
(let ((root (with-state
2009-03-13 17:29:32 +00:00
(translate (vector 0 0.5 (* 0.1 (rndf))))
2009-03-12 10:45:34 +00:00
(rotate (vector 0 0 180))
(texture (load-texture (string-append "textures/comp-" id ".png")))
(build-plane))))
(make-component root col '())))
2009-03-12 10:45:34 +00:00
(else
(let* ((connection-list (get-connection-list id))
(root (with-state
2009-03-13 17:29:32 +00:00
(translate (vector 0 0.5 (* 0.01 (rndf))))
2009-03-12 10:45:34 +00:00
(rotate (vector 0 0 180))
(texture (load-texture (string-append "textures/comp-" id ".png")))
(build-plane)))
(comp (make-component root col
2009-03-12 10:45:34 +00:00
(map
(lambda (child connection)
(with-state
(parent root)
2009-03-13 17:29:32 +00:00
(translate (vadd connection (vector 0 0 (* 0.01 (rndf)))))
2009-03-12 10:45:34 +00:00
(rotate (vector 0 0 (2dvec->angle
(vx connection) (- (vy connection) 0.5))))
(rotate (vector 0 0 0))
(build-component (car child) col (cadr child))))
2009-03-12 10:45:34 +00:00
children
connection-list))))
(with-primitive root (apply-transform))
comp))))
(define (random-leaf component)
(cond
((null? (component-children component)) component)
(else (random-leaf (choose (component-children component))))))
(define (component-leaves component)
(cond
((null? (component-children component)) (list component))
(else
(foldl
(lambda (child r)
(append (component-leaves child) r))
'()
(component-children component)))))
2009-03-12 10:45:34 +00:00
(define (component-print component)
(printf "~a~n" (component-children component)))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; utils for building random plants
(define (choose l)
(list-ref l (random (length l))))
(define (make-random-plant depth)
(let ((num-children (cond ((> depth 2) 0)
((< depth 1) (choose (list 2 3)))
(else (choose (list 0 1 2 3))))))
2009-03-12 10:45:34 +00:00
(cond
((eq? num-children 0) (list (choose (list "11")) (list)))
2009-03-12 11:51:02 +00:00
((eq? num-children 1) (list "1-1" (list (make-random-plant (+ depth 1)))))
((eq? num-children 2) (list "2-1" (list (make-random-plant (+ depth 1))
2009-03-12 10:45:34 +00:00
(make-random-plant (+ depth 1)))))
2009-03-12 11:51:02 +00:00
((eq? num-children 3) (list "3-1" (list (make-random-plant (+ depth 1))
2009-03-12 10:45:34 +00:00
(make-random-plant (+ depth 1)) (make-random-plant (+ depth 1)))))
2009-03-12 11:51:02 +00:00
((eq? num-children 4) (list "4-1" (list (make-random-plant (+ depth 1))
2009-03-12 10:45:34 +00:00
(make-random-plant (+ depth 1)) (make-random-plant (+ depth 1))
(make-random-plant (+ depth 1)))))
2009-03-12 11:51:02 +00:00
((eq? num-children 5) (list "5-1" (list (make-random-plant (+ depth 1))
2009-03-12 10:45:34 +00:00
(make-random-plant (+ depth 1)) (make-random-plant (+ depth 1))
(make-random-plant (+ depth 1)) (make-random-plant (+ depth 1))))))))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; the world things live in
(define world%
(class object%
(init-field (size 1))
(field
(root 0)
(entity-list '())
(id 0)
(pollen 0)
(my-id 0))
2009-03-12 10:45:34 +00:00
(define/public (init)
(set! pollen (with-state
2009-03-13 17:29:32 +00:00
(translate (vector 0 0 0.2))
2009-03-12 10:45:34 +00:00
(texture (load-texture "textures/pollen.png"))
2009-03-13 17:29:32 +00:00
(build-particles 1000)))
2009-03-12 10:45:34 +00:00
(with-primitive pollen
(pdata-map!
(lambda (p)
2009-03-13 17:29:32 +00:00
(vmul (vector (crndf) (crndf) (+ 0.2 (* (rndf) 0.01))) 10))
2009-03-12 10:45:34 +00:00
"p")
(pdata-map!
(lambda (c)
(vector (rndf) (rndf) (rndf) 0.5))
"c")
(pdata-map!
(lambda (c)
(let ((s (* 0.2 (grndf))))
2009-03-12 10:45:34 +00:00
(vector s s 1)))
"s"))
#;(set! root (with-state
2009-03-13 17:29:32 +00:00
(rotate (vector 90 0 0))
2009-03-12 10:45:34 +00:00
(scale 100)
(build-plane)))
2009-03-13 17:29:32 +00:00
(with-state
2009-03-12 10:45:34 +00:00
; (parent root)
(with-state
2009-03-13 17:29:32 +00:00
(colour (vector 0.5 1 0.5))
2009-03-12 10:45:34 +00:00
(scale (vector 20 13 1))
2009-03-13 17:29:32 +00:00
(translate (vector 0 0.2 0))
2009-03-12 10:45:34 +00:00
(rotate (vector 0 0 180))
2009-03-13 17:29:32 +00:00
; (texture (load-texture "textures/hills.png"))
2009-03-12 10:45:34 +00:00
(hint-unlit)
(build-plane))
2009-03-13 17:29:32 +00:00
#;(with-state
(scale (vector 14 15 1))
(translate (vector 0 0.3 4.5))
2009-03-12 10:45:34 +00:00
(rotate (vector 0 0 180))
2009-03-13 17:29:32 +00:00
(texture (load-texture "textures/fg.png"))
2009-03-12 10:45:34 +00:00
(hint-unlit)
(build-plane))))
(define/public (get-entity-list)
entity-list)
(define/public (get-my-id)
my-id)
(define/public (make-my-plant)
2009-03-13 17:29:32 +00:00
(let* ((pos (vector (* (crndf) 5) 2 0.1))
(col (hsv->rgb (vector (rndf) 0.8 1)))
(desc (list (make-random-plant 0))))
(set! my-id (length entity-list))
(set-entity my-id (make-object plant% pos col desc))))
2009-03-12 10:45:34 +00:00
(define/public (get-entity id)
(foldl
(lambda (entity ret)
(if (eq? (send entity get-id) id)
entity
ret))
#f
entity-list))
(define/public (choose)
(list-ref entity-list (random (length entity-list))))
(define/public (set-entity id entity)
; if it already exists, destroy it
; (do we want to do this all the time?)
(when (get-entity id)
(destroy-entity id))
2009-03-12 10:45:34 +00:00
(send entity set-id! id)
(set! entity-list (cons entity entity-list)))
2009-03-12 10:45:34 +00:00
(define/public (destroy-entity id)
(set! entity-list
2009-03-12 10:45:34 +00:00
(filter
(lambda (entity)
(cond ((eq? (send entity get-id) id)
(send entity destroy-me)
2009-03-12 10:45:34 +00:00
#f)
(else #t)))
entity-list)))
(define/public (update network)
2009-03-12 10:45:34 +00:00
(with-primitive pollen
(animate-pollen))
; update my plant with player input
(when (get-entity my-id)
(send (get-entity my-id) player-update this network))
2009-03-12 10:45:34 +00:00
(for-each
(lambda (entity)
(send entity update this))
entity-list))
; pollen stuff
(define (animate-pollen)
(pdata-map!
(lambda (p)
(let* ((pp (vmul p 0.5))
(v (vector (- (noise (vx pp) (vy pp) (time)) 0.5)
(- (noise (vx pp) (+ (vy pp) 112.3) (time)) 0.5) 0)))
(vadd (vadd p (vmul v 0.2))
(vmul (vector (crndf) (crndf) 0) 0.01))))
"p"))
(define (cirndvec)
(let ((o (srndvec)))
(vector (vx o) (vy o) 0)))
(define/public (puff-pollen pos col size np)
(with-primitive pollen
(for ((i (in-range 0 np)))
2009-03-12 11:51:02 +00:00
(let ((c (random (pdata-size)))
(cc (vmul col 1)))
2009-03-13 17:29:32 +00:00
(pdata-set! "p" c (vadd (vmul (cirndvec) size)
(vadd pos (vector 0 0 (+ 0.2 (* (rndf) 0.01))))))
2009-03-12 11:51:02 +00:00
(pdata-set! "c" c (vector (vx cc) (vy cc) (vz cc) 0.5))))))
2009-03-12 10:45:34 +00:00
(define/public (suck-pollen pos size)
(with-primitive pollen
(pdata-index-fold
(lambda (i p c r)
(cond ((< (vdist pos p) (/ size 10))
(pdata-set! "p" i (vector -1000 0 0))
(cons c r))
((< (vdist pos p) size)
(pdata-set! "p" i (vadd p
(vmul (vnormalise (vsub pos p)) 0.1)))
r)
(else r)))
'()
"p" "c")))
2009-03-12 10:45:34 +00:00
(super-new)
(init)))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; the entity base class
(define entity%
(class object%
(init-field (id 0))
(define/public (get-id)
id)
(define/public (set-id! s)
(set! id s))
(super-new)))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; finally, a plant...
(define plant%
(class entity%
(init-field
(pos (vector 0 0 0))
(col (vector 1 1 1))
(plant-desc '())
(flower-list '())
(current-flower 0))
2009-03-12 10:45:34 +00:00
(field
(root-component 0)
(spray-t 0))
(define/public (get-pos)
pos)
(define/public (get-col)
col)
(define/public (get-desc)
plant-desc)
2009-03-12 10:45:34 +00:00
(define/public (init)
(with-state
;(parent (send world get-root))
(colour col)
2009-03-12 10:45:34 +00:00
(hint-unlit)
(translate pos)
(printf "building from:~a~n" plant-desc)
(set! root-component (build-component "1-1" col plant-desc))
(set! flower-list (component-leaves root-component))))
(define/public (destroy-me)
(destroy (component-root root-component)))
2009-03-12 10:45:34 +00:00
(define/public (player-update world network)
(when (key-special-pressed 100)
(set! current-flower (modulo (+ current-flower 1) (length flower-list))))
(when (key-special-pressed 102)
(set! current-flower (modulo (- current-flower 1) (length flower-list))))
; bit odd, have to go through network to tell other clients to
; spray, and need to get the id of the player plant from the world...
(when (key-special-pressed 101)
(send network spray world (send world get-my-id) current-flower 0))
(let ((flower (list-ref flower-list current-flower)))
(with-primitive (component-root flower)
(when (key-special-pressed 103)
(rotate (vector 0 0 20))
(let ((colours (suck world current-flower)))
(when (not (zero? (length colours)))
(let
((av-col (vdiv (foldl vadd (vector 0 0 0) colours) (length colours))))
(set-component-col! flower
(vadd (vmul (component-col flower) 0.9)
(vmul av-col 0.1)))
(send network flower-update world (send world get-my-id)
current-flower (component-col flower))))))
(rotate (vector 0 0 2)))))
(define/public (flower-update flower col)
(let ((flower (list-ref flower-list flower)))
(set-component-col! flower col)
(with-primitive (component-root flower)
(colour (component-col flower)))))
2009-03-12 10:45:34 +00:00
(define/public (update world)
0
#;(with-primitive root
(colour col)
(when (> spray-t 1)
(set! spray-t (* spray-t 0.9))
(colour spray-t))))
(define/public (spray world flower type)
(let ((pos (vtransform (vector 0 0 0)
(with-primitive (component-root (list-ref flower-list flower))
(get-global-transform)))))
(send world puff-pollen pos (component-col (list-ref flower-list flower))
2009-03-13 17:29:32 +00:00
0.2 1)))
(define/public (suck world flower)
2009-03-12 10:45:34 +00:00
(let ((pos (vtransform (vector 0 0 0)
(with-primitive (component-root (list-ref flower-list flower))
2009-03-12 10:45:34 +00:00
(get-global-transform)))))
(send world suck-pollen pos 5)))
2009-03-12 10:45:34 +00:00
(super-new)
(init)))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(define network-dispatch%
(class object%
(field
(waiting #f)
(wait-till 0))
2009-03-12 11:51:02 +00:00
(define (stringify l)
(cond
((null? l) l)
((symbol? (car l))
(cons (symbol->string (car l))
(stringify (cdr l))))
((number? (car l))
(cons (number->string (car l))
(stringify (cdr l))))
((vector? (car l))
(cons (car l)
(stringify (cdr l))))
2009-03-12 11:51:02 +00:00
((list? (car l))
(cons (stringify (car l)) (stringify (cdr l))))
(else (error "oops"))))
(define (dispatch world)
2009-03-12 10:45:34 +00:00
(cond
((osc-msg "/join-game")
(printf "a new plant has joined the game~n")
; send a plant update for the new player
(update-plant world) )
((osc-msg "/plant")
(printf "add plant message recieved : ~a~n" (osc 0))
(send world set-entity (osc 0) (make-object plant%
(vector (osc 1) (osc 2) (osc 3))
(vector (osc 4) (osc 5) (osc 6))
(stringify (eval-string (osc 7))))))
((osc-msg "/flower")
2009-03-13 17:29:32 +00:00
;(printf "flower change msg recieved~n")
(send (send world get-entity (osc 0)) flower-update
(osc 1) (vector (osc 2) (osc 3) (osc 4))))
2009-03-12 10:45:34 +00:00
((osc-msg "/destroy-plant")
(printf "destroy plant message recieved...~n")
(send world destroy-entity (osc 0)))
2009-03-12 10:45:34 +00:00
((osc-msg "/spray")
; (printf "destroy plant message recieved...~n")
(let ((e (send world get-entity (osc 0))))
; it's possible to get spray events before the
; plant has been created...
(when e
(send e spray world (osc 1) (osc 2)))))))
2009-03-12 10:45:34 +00:00
(define/public (join-game world)
(printf "sending join-game~n")
(osc-send "/join-game" "" (list))
(set! wait-till (+ (time) 2))
(set! waiting #t))
(define/public (update-plant world)
(printf "sending /plant...~n")
2009-03-12 11:51:02 +00:00
(let* ((my-plant (send world get-entity (send world get-my-id)))
(pos (send my-plant get-pos))
(col (send my-plant get-col))
(desc-str (format "'~a" (send my-plant get-desc))))
(osc-send "/plant" "iffffffs" (list (send world get-my-id)
(vx pos) (vy pos) (vz pos)
(vx col) (vy col) (vz col)
desc-str))))
2009-03-12 10:45:34 +00:00
(define/public (destroy-plant world id)
(printf "sending destroy plant...~n")
(osc-send "/destroy-plant" "i" (list id))
(send world destroy-entity id))
(define/public (spray world id flower type)
(osc-send "/spray" "iii" (list id flower type))
(send (send world get-entity id) spray world flower type))
(define/public (flower-update world id flower col)
(osc-send "/flower" "iifff" (list id flower (vx col) (vy col) (vz col)))
(send (send world get-entity id) flower-update flower col))
(define/public (update world)
; wait for all other players to register their plants
(when (and waiting (< wait-till (time)))
(set! waiting #f)
(send world make-my-plant)
(update-plant world))
(dispatch world))
2009-03-12 10:45:34 +00:00
(super-new)))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(clear)
2009-03-13 17:29:32 +00:00
(clear-colour (vector 0.5 0.5 1))
(hint-depth-sort)
2009-03-12 10:45:34 +00:00
(set-camera-transform (mtranslate (vector 0 -5 -10)))
(define w (make-object world% 1))
(define n (make-object network-dispatch%))
(send n join-game w)
2009-03-12 10:45:34 +00:00
(define (animate)
(send n update w)
(send w update n))
2009-03-12 10:45:34 +00:00
(every-frame (animate))