Introduce sprite variables
This commit is contained in:
parent
55e4dabea9
commit
6d311f04d6
28
bot/bot.rkt
28
bot/bot.rkt
|
@ -19,25 +19,27 @@
|
|||
|
||||
(define (bouncy-box)
|
||||
(define me (symbol->string (strong-gensym 'user)))
|
||||
(define start-time (current-inexact-milliseconds))
|
||||
(define-field deadline start-time)
|
||||
(define-field x (* (- (random) 0.5) 100))
|
||||
|
||||
(define x (* (- (random) 0.5) 100))
|
||||
(define y0 (+ 1.0 (* (random) 10)))
|
||||
(define-field y y0)
|
||||
(define-field z (* (- (random) 0.5) 100))
|
||||
(at ds
|
||||
(on (asserted (LaterThan (deadline)))
|
||||
(deadline (+ (deadline) (/ 1000 10)))
|
||||
(y (+ y0 (cos (/ (- (deadline) start-time) 1000.0 (/ 1 2 pi)))))))
|
||||
(define z (* (- (random) 0.5) 100))
|
||||
(define r (random))
|
||||
(define g (random))
|
||||
(define b (random))
|
||||
|
||||
(define-field y y0)
|
||||
(define start-time (current-inexact-milliseconds))
|
||||
(define-field deadline start-time)
|
||||
(at ds
|
||||
(on (asserted (LaterThan (deadline)))
|
||||
(deadline (+ (deadline) (/ 1000 30)))
|
||||
(y (+ y0 (cos (/ (- (deadline) start-time) 1000.0 (/ 1 2 pi)))))))
|
||||
|
||||
(at scene
|
||||
(assert (Sprite me (Move (Vector3 (x) (y) (z))
|
||||
(Color-opaque r g b (Box)))))
|
||||
))
|
||||
(assert (Variable me 'y (y)))
|
||||
(assert (Sprite me '(y) (Move (ImmediateVector3 x 'y z) (Color-opaque r g b (Box)))))))
|
||||
|
||||
(for [(i 100)] (bouncy-box)))))
|
||||
|
||||
(run-tcp-client-relay ds #:hostname "vr.demo.leastfixedpoint.com" #:port 9001
|
||||
(run-tcp-client-relay ds #:hostname "localhost" #;"vr.demo.leastfixedpoint.com" #:port 9001
|
||||
#:import (lambda (v) (on-connected (embedded-value v))))))
|
||||
|
|
|
@ -59,7 +59,10 @@
|
|||
((and dest
|
||||
(record
|
||||
'gravity
|
||||
(list (app shapes:parse-Vector3 (and ?direction (not (== eof)))))))
|
||||
(list
|
||||
(app
|
||||
shapes:parse-LiteralVector3
|
||||
(and ?direction (not (== eof)))))))
|
||||
(Gravity ?direction))
|
||||
(_ eof)))
|
||||
(define parse-Gravity! (parse-success-or-error 'parse-Gravity parse-Gravity))
|
||||
|
@ -89,7 +92,9 @@
|
|||
(list
|
||||
(and ?name (? string?))
|
||||
(app parse-PortalDestination (and ?destination (not (== eof))))
|
||||
(app shapes:parse-Vector3 (and ?position (not (== eof)))))))
|
||||
(app
|
||||
shapes:parse-LiteralVector3
|
||||
(and ?position (not (== eof)))))))
|
||||
(Portal ?name ?destination ?position))
|
||||
(_ eof)))
|
||||
(define parse-Portal! (parse-success-or-error 'parse-Portal parse-Portal))
|
||||
|
|
|
@ -172,21 +172,21 @@
|
|||
(record
|
||||
'scale
|
||||
(list
|
||||
(app parse-Vector3 (and ?v (not (== eof))))
|
||||
(app parse-LiteralVector3 (and ?v (not (== eof))))
|
||||
(app parse-CSGExpr (and ?shape (not (== eof)))))))
|
||||
(CSGExpr-scale ?v ?shape))
|
||||
((and dest
|
||||
(record
|
||||
'move
|
||||
(list
|
||||
(app parse-Vector3 (and ?v (not (== eof))))
|
||||
(app parse-LiteralVector3 (and ?v (not (== eof))))
|
||||
(app parse-CSGExpr (and ?shape (not (== eof)))))))
|
||||
(CSGExpr-move ?v ?shape))
|
||||
((and dest
|
||||
(record
|
||||
'rotate
|
||||
(list
|
||||
(app parse-Vector3 (and ?v (not (== eof))))
|
||||
(app parse-LiteralVector3 (and ?v (not (== eof))))
|
||||
(app parse-CSGExpr (and ?shape (not (== eof)))))))
|
||||
(CSGExpr-rotate ?v ?shape))
|
||||
((and dest
|
||||
|
@ -235,9 +235,9 @@
|
|||
(record
|
||||
'color
|
||||
(list
|
||||
(exact->inexact (*->preserve ?r))
|
||||
(exact->inexact (*->preserve ?g))
|
||||
(exact->inexact (*->preserve ?b))
|
||||
(*->preserve ?r)
|
||||
(*->preserve ?g)
|
||||
(*->preserve ?b)
|
||||
(*->preserve ?shape))))))))
|
||||
(struct
|
||||
Color-transparent
|
||||
|
@ -253,10 +253,10 @@
|
|||
(record
|
||||
'color
|
||||
(list
|
||||
(exact->inexact (*->preserve ?r))
|
||||
(exact->inexact (*->preserve ?g))
|
||||
(exact->inexact (*->preserve ?b))
|
||||
(exact->inexact (*->preserve ?alpha))
|
||||
(*->preserve ?r)
|
||||
(*->preserve ?g)
|
||||
(*->preserve ?b)
|
||||
(*->preserve ?alpha)
|
||||
(*->preserve ?shape))))))))
|
||||
(define (parse-Color input)
|
||||
(match
|
||||
|
@ -265,23 +265,53 @@
|
|||
(record
|
||||
'color
|
||||
(list
|
||||
(and ?r (? flonum?))
|
||||
(and ?g (? flonum?))
|
||||
(and ?b (? flonum?))
|
||||
(app parse-DoubleValue (and ?r (not (== eof))))
|
||||
(app parse-DoubleValue (and ?g (not (== eof))))
|
||||
(app parse-DoubleValue (and ?b (not (== eof))))
|
||||
(app parse-Shape (and ?shape (not (== eof)))))))
|
||||
(Color-opaque ?r ?g ?b ?shape))
|
||||
((and dest
|
||||
(record
|
||||
'color
|
||||
(list
|
||||
(and ?r (? flonum?))
|
||||
(and ?g (? flonum?))
|
||||
(and ?b (? flonum?))
|
||||
(and ?alpha (? flonum?))
|
||||
(app parse-DoubleValue (and ?r (not (== eof))))
|
||||
(app parse-DoubleValue (and ?g (not (== eof))))
|
||||
(app parse-DoubleValue (and ?b (not (== eof))))
|
||||
(app parse-DoubleValue (and ?alpha (not (== eof))))
|
||||
(app parse-Shape (and ?shape (not (== eof)))))))
|
||||
(Color-transparent ?r ?g ?b ?alpha ?shape))
|
||||
(_ eof)))
|
||||
(define parse-Color! (parse-success-or-error 'parse-Color parse-Color))
|
||||
(define (DoubleValue? p)
|
||||
(or (DoubleValue-immediate? p) (DoubleValue-reference? p)))
|
||||
(struct
|
||||
DoubleValue-immediate
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((DoubleValue-immediate src) (exact->inexact (*->preserve src)))))))
|
||||
(struct
|
||||
DoubleValue-reference
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((DoubleValue-reference src) (*->preserve src))))))
|
||||
(define (parse-DoubleValue input)
|
||||
(match
|
||||
input
|
||||
((and dest (? flonum?)) (DoubleValue-immediate dest))
|
||||
((and dest (? symbol?)) (DoubleValue-reference dest))
|
||||
(_ eof)))
|
||||
(define parse-DoubleValue!
|
||||
(parse-success-or-error 'parse-DoubleValue parse-DoubleValue))
|
||||
(struct
|
||||
External
|
||||
(path)
|
||||
|
@ -324,7 +354,19 @@
|
|||
(define parse-Floor! (parse-success-or-error 'parse-Floor parse-Floor))
|
||||
(struct
|
||||
Ground
|
||||
(size)
|
||||
()
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Ground) (record 'ground (list)))))))
|
||||
(define (parse-Ground input)
|
||||
(match input ((and dest (record 'ground (list))) (Ground)) (_ eof)))
|
||||
(define parse-Ground! (parse-success-or-error 'parse-Ground parse-Ground))
|
||||
(struct
|
||||
ImmediateQuaternion
|
||||
(a b c d)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
|
@ -332,17 +374,84 @@
|
|||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((Ground ?size) (record 'ground (list (*->preserve ?size))))))))
|
||||
(define (parse-Ground input)
|
||||
((ImmediateQuaternion ?a ?b ?c ?d)
|
||||
(record
|
||||
'q
|
||||
(list
|
||||
(*->preserve ?a)
|
||||
(*->preserve ?b)
|
||||
(*->preserve ?c)
|
||||
(*->preserve ?d))))))))
|
||||
(define (parse-ImmediateQuaternion input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'ground
|
||||
(list (app parse-Vector2 (and ?size (not (== eof)))))))
|
||||
(Ground ?size))
|
||||
'q
|
||||
(list
|
||||
(app parse-DoubleValue (and ?a (not (== eof))))
|
||||
(app parse-DoubleValue (and ?b (not (== eof))))
|
||||
(app parse-DoubleValue (and ?c (not (== eof))))
|
||||
(app parse-DoubleValue (and ?d (not (== eof)))))))
|
||||
(ImmediateQuaternion ?a ?b ?c ?d))
|
||||
(_ eof)))
|
||||
(define parse-Ground! (parse-success-or-error 'parse-Ground parse-Ground))
|
||||
(define parse-ImmediateQuaternion!
|
||||
(parse-success-or-error
|
||||
'parse-ImmediateQuaternion
|
||||
parse-ImmediateQuaternion))
|
||||
(struct
|
||||
ImmediateVector2
|
||||
(x y)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((ImmediateVector2 ?x ?y)
|
||||
(record 'v (list (*->preserve ?x) (*->preserve ?y))))))))
|
||||
(define (parse-ImmediateVector2 input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'v
|
||||
(list
|
||||
(app parse-DoubleValue (and ?x (not (== eof))))
|
||||
(app parse-DoubleValue (and ?y (not (== eof)))))))
|
||||
(ImmediateVector2 ?x ?y))
|
||||
(_ eof)))
|
||||
(define parse-ImmediateVector2!
|
||||
(parse-success-or-error 'parse-ImmediateVector2 parse-ImmediateVector2))
|
||||
(struct
|
||||
ImmediateVector3
|
||||
(x y z)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((ImmediateVector3 ?x ?y ?z)
|
||||
(record
|
||||
'v
|
||||
(list (*->preserve ?x) (*->preserve ?y) (*->preserve ?z))))))))
|
||||
(define (parse-ImmediateVector3 input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'v
|
||||
(list
|
||||
(app parse-DoubleValue (and ?x (not (== eof))))
|
||||
(app parse-DoubleValue (and ?y (not (== eof))))
|
||||
(app parse-DoubleValue (and ?z (not (== eof)))))))
|
||||
(ImmediateVector3 ?x ?y ?z))
|
||||
(_ eof)))
|
||||
(define parse-ImmediateVector3!
|
||||
(parse-success-or-error 'parse-ImmediateVector3 parse-ImmediateVector3))
|
||||
(struct
|
||||
Light
|
||||
(v)
|
||||
|
@ -364,6 +473,37 @@
|
|||
(Light ?v))
|
||||
(_ eof)))
|
||||
(define parse-Light! (parse-success-or-error 'parse-Light parse-Light))
|
||||
(struct
|
||||
LiteralVector3
|
||||
(x y z)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((LiteralVector3 ?x ?y ?z)
|
||||
(record
|
||||
'v
|
||||
(list
|
||||
(exact->inexact (*->preserve ?x))
|
||||
(exact->inexact (*->preserve ?y))
|
||||
(exact->inexact (*->preserve ?z)))))))))
|
||||
(define (parse-LiteralVector3 input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'v
|
||||
(list
|
||||
(and ?x (? flonum?))
|
||||
(and ?y (? flonum?))
|
||||
(and ?z (? flonum?)))))
|
||||
(LiteralVector3 ?x ?y ?z))
|
||||
(_ eof)))
|
||||
(define parse-LiteralVector3!
|
||||
(parse-success-or-error 'parse-LiteralVector3 parse-LiteralVector3))
|
||||
(define (Mesh? p)
|
||||
(or (Mesh-Sphere? p)
|
||||
(Mesh-Box? p)
|
||||
|
@ -508,36 +648,32 @@
|
|||
(define (parse-Plane input)
|
||||
(match input ((and dest (record 'plane (list))) (Plane)) (_ eof)))
|
||||
(define parse-Plane! (parse-success-or-error 'parse-Plane parse-Plane))
|
||||
(define (Quaternion? p)
|
||||
(or (Quaternion-immediate? p) (Quaternion-reference? p)))
|
||||
(struct
|
||||
Quaternion
|
||||
(a b c d)
|
||||
Quaternion-immediate
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((Quaternion ?a ?b ?c ?d)
|
||||
(record
|
||||
'q
|
||||
(list
|
||||
(exact->inexact (*->preserve ?a))
|
||||
(exact->inexact (*->preserve ?b))
|
||||
(exact->inexact (*->preserve ?c))
|
||||
(exact->inexact (*->preserve ?d)))))))))
|
||||
(match preservable ((Quaternion-immediate src) (*->preserve src))))))
|
||||
(struct
|
||||
Quaternion-reference
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Quaternion-reference src) (*->preserve src))))))
|
||||
(define (parse-Quaternion input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'q
|
||||
(list
|
||||
(and ?a (? flonum?))
|
||||
(and ?b (? flonum?))
|
||||
(and ?c (? flonum?))
|
||||
(and ?d (? flonum?)))))
|
||||
(Quaternion ?a ?b ?c ?d))
|
||||
((app parse-ImmediateQuaternion (and dest (not (== eof))))
|
||||
(Quaternion-immediate dest))
|
||||
((and dest (? symbol?)) (Quaternion-reference dest))
|
||||
(_ eof)))
|
||||
(define parse-Quaternion!
|
||||
(parse-success-or-error 'parse-Quaternion parse-Quaternion))
|
||||
|
@ -873,7 +1009,7 @@
|
|||
(define parse-Sphere! (parse-success-or-error 'parse-Sphere parse-Sphere))
|
||||
(struct
|
||||
Sprite
|
||||
(name shape)
|
||||
(name formals shape)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
|
@ -881,8 +1017,13 @@
|
|||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((Sprite ?name ?shape)
|
||||
(record 'sprite (list (*->preserve ?name) (*->preserve ?shape))))))))
|
||||
((Sprite ?name ?formals ?shape)
|
||||
(record
|
||||
'sprite
|
||||
(list
|
||||
(*->preserve ?name)
|
||||
(for/list ((item (in-list ?formals))) (*->preserve item))
|
||||
(*->preserve ?shape))))))))
|
||||
(define (parse-Sprite input)
|
||||
(match
|
||||
input
|
||||
|
@ -891,8 +1032,9 @@
|
|||
'sprite
|
||||
(list
|
||||
(and ?name (? string?))
|
||||
(list (and ?formals (? symbol?)) ...)
|
||||
(app parse-Shape (and ?shape (not (== eof)))))))
|
||||
(Sprite ?name ?shape))
|
||||
(Sprite ?name ?formals ?shape))
|
||||
(_ eof)))
|
||||
(define parse-Sprite! (parse-success-or-error 'parse-Sprite parse-Sprite))
|
||||
(struct
|
||||
|
@ -962,7 +1104,7 @@
|
|||
(*->preserve ?path)
|
||||
(*->preserve ?scale)
|
||||
(*->preserve ?offset)
|
||||
(exact->inexact (*->preserve ?alpha))))))))
|
||||
(*->preserve ?alpha)))))))
|
||||
(define (parse-TextureSpec input)
|
||||
(match
|
||||
input
|
||||
|
@ -978,7 +1120,7 @@
|
|||
(and ?path (? string?))
|
||||
(app parse-Vector2 (and ?scale (not (== eof))))
|
||||
(app parse-Vector2 (and ?offset (not (== eof))))
|
||||
(and ?alpha (? flonum?))))
|
||||
(app parse-DoubleValue (and ?alpha (not (== eof))))))
|
||||
(TextureSpec-uvAlpha ?path ?scale ?offset ?alpha))
|
||||
(_ eof)))
|
||||
(define parse-TextureSpec!
|
||||
|
@ -1006,8 +1148,8 @@
|
|||
(define parse-Touchable!
|
||||
(parse-success-or-error 'parse-Touchable parse-Touchable))
|
||||
(struct
|
||||
Vector2
|
||||
(x y)
|
||||
Variable
|
||||
(spriteName variable value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
|
@ -1015,47 +1157,79 @@
|
|||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((Vector2 ?x ?y)
|
||||
((Variable ?spriteName ?variable ?value)
|
||||
(record
|
||||
'v
|
||||
'variable
|
||||
(list
|
||||
(exact->inexact (*->preserve ?x))
|
||||
(exact->inexact (*->preserve ?y)))))))))
|
||||
(define (parse-Vector2 input)
|
||||
(match
|
||||
input
|
||||
((and dest (record 'v (list (and ?x (? flonum?)) (and ?y (? flonum?)))))
|
||||
(Vector2 ?x ?y))
|
||||
(_ eof)))
|
||||
(define parse-Vector2! (parse-success-or-error 'parse-Vector2 parse-Vector2))
|
||||
(struct
|
||||
Vector3
|
||||
(x y z)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match
|
||||
preservable
|
||||
((Vector3 ?x ?y ?z)
|
||||
(record
|
||||
'v
|
||||
(list
|
||||
(exact->inexact (*->preserve ?x))
|
||||
(exact->inexact (*->preserve ?y))
|
||||
(exact->inexact (*->preserve ?z)))))))))
|
||||
(define (parse-Vector3 input)
|
||||
(*->preserve ?spriteName)
|
||||
(*->preserve ?variable)
|
||||
(*->preserve ?value))))))))
|
||||
(define (parse-Variable input)
|
||||
(match
|
||||
input
|
||||
((and dest
|
||||
(record
|
||||
'v
|
||||
'variable
|
||||
(list
|
||||
(and ?x (? flonum?))
|
||||
(and ?y (? flonum?))
|
||||
(and ?z (? flonum?)))))
|
||||
(Vector3 ?x ?y ?z))
|
||||
(and ?spriteName (? string?))
|
||||
(and ?variable (? symbol?))
|
||||
?value)))
|
||||
(Variable ?spriteName ?variable ?value))
|
||||
(_ eof)))
|
||||
(define parse-Variable!
|
||||
(parse-success-or-error 'parse-Variable parse-Variable))
|
||||
(define (Vector2? p) (or (Vector2-immediate? p) (Vector2-reference? p)))
|
||||
(struct
|
||||
Vector2-immediate
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Vector2-immediate src) (*->preserve src))))))
|
||||
(struct
|
||||
Vector2-reference
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Vector2-reference src) (*->preserve src))))))
|
||||
(define (parse-Vector2 input)
|
||||
(match
|
||||
input
|
||||
((app parse-ImmediateVector2 (and dest (not (== eof))))
|
||||
(Vector2-immediate dest))
|
||||
((and dest (? symbol?)) (Vector2-reference dest))
|
||||
(_ eof)))
|
||||
(define parse-Vector2! (parse-success-or-error 'parse-Vector2 parse-Vector2))
|
||||
(define (Vector3? p) (or (Vector3-immediate? p) (Vector3-reference? p)))
|
||||
(struct
|
||||
Vector3-immediate
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Vector3-immediate src) (*->preserve src))))))
|
||||
(struct
|
||||
Vector3-reference
|
||||
(value)
|
||||
#:transparent
|
||||
#:methods
|
||||
gen:preservable
|
||||
((define/generic *->preserve ->preserve)
|
||||
(define (->preserve preservable)
|
||||
(match preservable ((Vector3-reference src) (*->preserve src))))))
|
||||
(define (parse-Vector3 input)
|
||||
(match
|
||||
input
|
||||
((app parse-ImmediateVector3 (and dest (not (== eof))))
|
||||
(Vector3-immediate dest))
|
||||
((and dest (? symbol?)) (Vector3-reference dest))
|
||||
(_ eof)))
|
||||
(define parse-Vector3!
|
||||
(parse-success-or-error 'parse-Vector3 parse-Vector3)))
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
version 1 .
|
||||
|
||||
Portal = <portal @name string @destination PortalDestination @position shapes.Vector3> .
|
||||
Portal = <portal @name string @destination PortalDestination @position shapes.LiteralVector3> .
|
||||
PortalDestination =
|
||||
/ @local #!any
|
||||
/ @remote noise.Route
|
||||
.
|
||||
|
||||
Gravity = <gravity @direction shapes.Vector3> .
|
||||
Gravity = <gravity @direction shapes.LiteralVector3> .
|
||||
|
||||
AmbientSound = <ambient-sound @name string @spec shapes.SoundSpec> .
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
version 1 .
|
||||
|
||||
Sprite = <sprite @name string @shape Shape> .
|
||||
Sprite = <sprite @name string @formals [symbol ...] @shape Shape> .
|
||||
Variable = <variable @spriteName string @variable symbol @value any> .
|
||||
|
||||
Shape = Mesh / Light / Scale / Move / Rotate / @many [Shape ...] / Texture / Color / Sound / Name / Floor / Nonphysical / Touchable / CSG / Skybox .
|
||||
|
||||
|
@ -8,15 +9,23 @@ Mesh = Sphere / Box / Ground / Plane / External .
|
|||
|
||||
Sphere = <sphere> .
|
||||
Box = <box> .
|
||||
Ground = <ground @size Vector2> .
|
||||
Ground = <ground> .
|
||||
Plane = <plane> .
|
||||
External = <external @path string> .
|
||||
|
||||
Light = <hemispheric-light @v Vector3> .
|
||||
|
||||
Vector2 = <v @x double @y double> .
|
||||
Vector3 = <v @x double @y double @z double> .
|
||||
Quaternion = <q @a double @b double @c double @d double> .
|
||||
DoubleValue = @immediate double / @reference symbol .
|
||||
|
||||
ImmediateVector2 = <v @x DoubleValue @y DoubleValue> .
|
||||
ImmediateVector3 = <v @x DoubleValue @y DoubleValue @z DoubleValue> .
|
||||
ImmediateQuaternion = <q @a DoubleValue @b DoubleValue @c DoubleValue @d DoubleValue> .
|
||||
|
||||
LiteralVector3 = <v @x double @y double @z double> .
|
||||
|
||||
Vector2 = @immediate ImmediateVector2 / @reference symbol .
|
||||
Vector3 = @immediate ImmediateVector3 / @reference symbol .
|
||||
Quaternion = @immediate ImmediateQuaternion / @reference symbol .
|
||||
|
||||
Scale = <scale @v Vector3 @shape Shape> .
|
||||
Move = <move @v Vector3 @shape Shape> .
|
||||
|
@ -26,12 +35,12 @@ Texture = <texture @spec TextureSpec @shape Shape> .
|
|||
TextureSpec =
|
||||
/ @simple [@path string]
|
||||
/ @uv [@path string @scale Vector2 @offset Vector2]
|
||||
/ @uvAlpha [@path string @scale Vector2 @offset Vector2 @alpha double]
|
||||
/ @uvAlpha [@path string @scale Vector2 @offset Vector2 @alpha DoubleValue]
|
||||
.
|
||||
|
||||
Color =
|
||||
/ @opaque <color @r double @g double @b double @shape Shape>
|
||||
/ @transparent <color @r double @g double @b double @alpha double @shape Shape>
|
||||
/ @opaque <color @r DoubleValue @g DoubleValue @b DoubleValue @shape Shape>
|
||||
/ @transparent <color @r DoubleValue @g DoubleValue @b DoubleValue @alpha DoubleValue @shape Shape>
|
||||
.
|
||||
|
||||
Sound = <sound @spec SoundSpec @shape Shape> .
|
||||
|
@ -50,9 +59,9 @@ CSG = <csg @expr CSGExpr> .
|
|||
|
||||
CSGExpr =
|
||||
/ <mesh @shape Mesh>
|
||||
/ <scale @v Vector3 @shape CSGExpr>
|
||||
/ <move @v Vector3 @shape CSGExpr>
|
||||
/ <rotate @v Vector3 @shape CSGExpr>
|
||||
/ <scale @v LiteralVector3 @shape CSGExpr>
|
||||
/ <move @v LiteralVector3 @shape CSGExpr>
|
||||
/ <rotate @v LiteralVector3 @shape CSGExpr>
|
||||
/ <subtract [@base CSGExpr @more CSGExpr ...]>
|
||||
/ <union [@base CSGExpr @more CSGExpr ...]>
|
||||
/ <intersect [@base CSGExpr @more CSGExpr ...]>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<sprite "light" <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||
<sprite "light" [] <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||
<gravity <v 0.0 -9.81 0.0>>
|
||||
<sprite "sky" <skybox "textures/Daylight Box UV_0">>
|
||||
<sprite "sky" [] <skybox "textures/Daylight Box UV_0">>
|
||||
|
||||
<sprite "ground"
|
||||
<sprite "ground" []
|
||||
<texture ["textures/grass-256x256.jpg"
|
||||
<v 100.0 100.0>
|
||||
<v 0.0 0.0>]
|
||||
<floor <ground <v 300.0 300.0>>>>>
|
||||
<floor <scale <v 300.0 1.0 300.0> <ground>>>>>
|
||||
|
||||
<sprite "box"
|
||||
<sprite "box" []
|
||||
<move <v -6.0 1.0 8.0>
|
||||
<scale <v 10.0 0.1 10.0>
|
||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||
|
@ -17,20 +17,20 @@
|
|||
0.75]
|
||||
<floor <box>>>>>>
|
||||
|
||||
<sprite "box2"
|
||||
<sprite "box2" []
|
||||
<move <v -500.0 0.5 3.0>
|
||||
<floor
|
||||
<color 0.0 0.0 1.0 1.0
|
||||
<scale <v 1000.0 1.0 1.0> <box>>>>>>
|
||||
|
||||
<Exit "p" "lobby">
|
||||
<sprite "p"
|
||||
<sprite "p" []
|
||||
<move <v -999.5 2.0 3.0>
|
||||
<rotate <v 0.0 -0.25 0.0>
|
||||
<color 1.0 0.0 1.0
|
||||
<touchable <scale <v 1.0 2.0 1.0> <plane>>>>>>>
|
||||
|
||||
<sprite "steps"
|
||||
<sprite "steps" []
|
||||
<color 0.0 0.5 0.0
|
||||
<move <v 0.0 0.0 3.5>
|
||||
<scale <v 1.0 1.0 3.0>
|
||||
|
@ -42,8 +42,9 @@
|
|||
]>>>>>
|
||||
|
||||
<Exit "door" "other">
|
||||
<sprite "door"
|
||||
<move <v -3.0 0.0 1.5>
|
||||
<variable "door" y 0.0>
|
||||
<sprite "door" [y]
|
||||
<move <v -3.0 y 1.5>
|
||||
<rotate <v 0.0 -0.1 0.0> [
|
||||
<scale <v 1.0 2.11 1.0>
|
||||
<texture ["textures/door1.jpg"]
|
||||
|
@ -52,7 +53,7 @@
|
|||
]>>>
|
||||
|
||||
<portal "door2" <route [<ws "wss://vr.demo.eighty-twenty.org/ws">]>>
|
||||
<sprite "door2"
|
||||
<sprite "door2" []
|
||||
<move <v -5.0 0.0 1.5>
|
||||
<rotate <v 0.0 -0.1 0.0> [
|
||||
<scale <v 1.0 2.11 1.0>
|
||||
|
@ -61,14 +62,14 @@
|
|||
<scale <v 1.0 2.11 0.1> <move <v 0.0 0.5 0.6> <box>>>
|
||||
]>>>
|
||||
|
||||
<sprite "plans"
|
||||
<sprite "plans" []
|
||||
<texture ["plans/signal-2022-12-27-125451_002.jpeg"]
|
||||
<move <v 0.0 1.0 -10.0>
|
||||
<rotate <v 0.1 0.0 0.0>
|
||||
<scale <v 2.0 2.0 0.1>
|
||||
<box>>>>>>
|
||||
|
||||
<sprite "tower"
|
||||
<sprite "tower" []
|
||||
<rotate <v 0.1 0.0 0.0>
|
||||
<move <v -10.0 50.0 13.0>
|
||||
<scale <v 3.0 100.0 3.0>
|
||||
|
@ -76,7 +77,7 @@
|
|||
<color 0.5 0.5 0.0
|
||||
<box>>>>>>>
|
||||
|
||||
; <sprite "sponge"
|
||||
; <sprite "sponge" []
|
||||
; <move <v 4.0 1.6 0.0> [
|
||||
; <scale <v 0.001 0.001 0.001>
|
||||
; <external "objects/usnm_346-100k-obj/usnm_346-01-100k.obj">>
|
||||
|
@ -86,12 +87,12 @@
|
|||
; <box>>>>
|
||||
; ]>>
|
||||
|
||||
; <sprite "sofa"
|
||||
; <sprite "sofa" []
|
||||
; <rotate <v -0.125 0.5 0.0>
|
||||
; <scale <v 0.01 0.01 0.01>
|
||||
; <external "objects/IKE020001_obj/IKEA-Arild_2_Seat_Sofa-3D.obj">>>>
|
||||
|
||||
<sprite "x"
|
||||
<sprite "x" []
|
||||
<move <v 10.0 1.6 -5.0>
|
||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||
<v 1.0 3.0 1.0>
|
||||
|
@ -105,7 +106,7 @@
|
|||
>>>>>
|
||||
|
||||
; <Exit "y" "lobby">
|
||||
; <sprite "y"
|
||||
; <sprite "y" []
|
||||
; <move <v 12.0 0.75 -5.0>
|
||||
; <texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||
; <v 1.0 1.0 1.0>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<sprite "light" <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||
<sprite "light" [] <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||
;<gravity <v 0.0 -9.81 0.0>>
|
||||
<sprite "sky" <skybox "textures/eso0932a">>
|
||||
<sprite "sky" [] <skybox "textures/eso0932a">>
|
||||
|
||||
<ambient-sound "space" <loop "sounds/Space-atmosphere-sound/Space-atmosphere-sound.mp3">>
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
|||
; <floor <ground <v 300.0 300.0>>>>>
|
||||
|
||||
<Exit "home" "lobby" <v -2.5 0.0 0.5>>
|
||||
<sprite "home"
|
||||
<sprite "home" []
|
||||
<move <v 0.0 0.0 -2.0>
|
||||
<rotate <v 0.0 -0.5 0.0> [
|
||||
<scale <v 1.0 2.11 1.0>
|
||||
|
@ -20,7 +20,7 @@
|
|||
<scale <v 1.0 2.11 0.1> <move <v 0.0 0.5 0.6> <box>>>
|
||||
]>>>
|
||||
|
||||
<sprite "x"
|
||||
<sprite "x" []
|
||||
<move <v 0.0 0.0 10.0>
|
||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||
<v 1.0 3.0 1.0>
|
||||
|
|
84
src/index.ts
84
src/index.ts
|
@ -1,4 +1,4 @@
|
|||
import { is, fromJS, Dataflow, Dataspace, Embedded, Reader, Ref, Schemas, Sturdy, Turn } from "@syndicate-lang/core";
|
||||
import { is, fromJS, Dataflow, Dataspace, Embedded, Ref, Schemas, Turn } from "@syndicate-lang/core";
|
||||
import * as html from "@syndicate-lang/html";
|
||||
import * as timer from "@syndicate-lang/timer";
|
||||
import * as wsRelay from "@syndicate-lang/ws-relay";
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
Vector3,
|
||||
} from '@babylonjs/core/Legacy/legacy';
|
||||
|
||||
import { activeFloorMeshes, activeTouchableMeshes, ShapeTree, v3, scale3, buildSound, builder as B } from './shapes.js';
|
||||
import { activeFloorMeshes, activeTouchableMeshes, Environment, ShapeTree, buildSound, builder as B, u2, u3, u3v } from './shapes.js';
|
||||
import { RunningEngine } from './engine.js';
|
||||
import { uuid } from './uuid.js';
|
||||
|
||||
|
@ -22,13 +22,14 @@ assertion type SceneHandle(ds: Embedded<Ref>);
|
|||
|
||||
function interpretScene(myId: string, runningEngine: RunningEngine, rootMesh: Mesh, sceneDs: Ref) {
|
||||
at sceneDs {
|
||||
during Shapes.Sprite({ "name": $name: string }) => spawn named `sprite:${name}` {
|
||||
during Shapes.Sprite({ "name": $name: string, "formals": $formals }) => spawn named `sprite:${name}` {
|
||||
if (name === myId) {
|
||||
console.log('ignoring sprite', name);
|
||||
} else {
|
||||
console.log('+shape', name);
|
||||
on stop console.log('-shape', name);
|
||||
spriteMain(name, runningEngine, rootMesh, sceneDs);
|
||||
const env = new Environment(name, formals as symbol[], sceneDs);
|
||||
spriteMain(env, runningEngine, rootMesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,20 +43,20 @@ function interpretScene(myId: string, runningEngine: RunningEngine, rootMesh: Me
|
|||
}
|
||||
}
|
||||
|
||||
function spriteMain(spriteName: string, runningEngine: RunningEngine, rootMesh: Mesh, sceneDs: Ref) {
|
||||
at sceneDs {
|
||||
let currentShape = ShapeTree.empty(spriteName, runningEngine.scene);
|
||||
function spriteMain(env: Environment, runningEngine: RunningEngine, rootMesh: Mesh) {
|
||||
at env.sceneDs {
|
||||
let currentShape = ShapeTree.empty(env.spriteName, runningEngine.scene);
|
||||
currentShape.rootnode.parent = rootMesh;
|
||||
on stop currentShape.remove();
|
||||
during Shapes.Sprite({ "name": spriteName, "shape": $shape: Shapes.Shape }) => {
|
||||
currentShape = currentShape.reconcile(spriteName, spriteName, shape);
|
||||
during Shapes.Sprite({ "name": env.spriteName, "shape": $shape: Shapes.Shape }) => {
|
||||
currentShape = currentShape.reconcile(env, env.spriteName, shape);
|
||||
currentShape.rootnode.parent = rootMesh;
|
||||
}
|
||||
|
||||
during SceneProtocol.Gravity($direction: Shapes.Vector3) => {
|
||||
during SceneProtocol.Gravity($direction: Shapes.LiteralVector3) => {
|
||||
runningEngine.applyGravity = true;
|
||||
on stop runningEngine.applyGravity = false;
|
||||
runningEngine.gravity = v3(direction);
|
||||
runningEngine.gravity = new Vector3(direction.x, direction.y, direction.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,21 +102,23 @@ async function enterScene(
|
|||
}
|
||||
};
|
||||
|
||||
const currentPosition = () => Shapes.Vector3(runningEngine.position);
|
||||
const currentRotation = () => Shapes.Vector3(runningEngine.rotation);
|
||||
const TAU = 2 * Math.PI;
|
||||
|
||||
field position: Shapes.Vector3 = currentPosition();
|
||||
field rotation: Shapes.Vector3 = currentRotation();
|
||||
const currentPosition = () => u3(runningEngine.position);
|
||||
const currentRotation = () => u3(runningEngine.rotation, 1/TAU);
|
||||
|
||||
field position: Shapes.ImmediateVector3 = currentPosition();
|
||||
field rotation: Shapes.ImmediateVector3 = currentRotation();
|
||||
|
||||
const refreshPeriod = Math.floor(1000 / 10);
|
||||
at ds {
|
||||
on message timer.PeriodicTick(refreshPeriod) => {
|
||||
const newPosition = currentPosition();
|
||||
const newRotation = currentRotation();
|
||||
if (!is(Shapes.fromVector3(position.value), Shapes.fromVector3(newPosition))) {
|
||||
if (!is(Shapes.fromImmediateVector3(position.value), Shapes.fromImmediateVector3(newPosition))) {
|
||||
position.value = newPosition;
|
||||
}
|
||||
if (!is(Shapes.fromVector3(rotation.value), Shapes.fromVector3(newRotation))) {
|
||||
if (!is(Shapes.fromImmediateVector3(rotation.value), Shapes.fromImmediateVector3(newRotation))) {
|
||||
rotation.value = newRotation;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +131,7 @@ async function enterScene(
|
|||
on asserted SceneProtocol.Portal({
|
||||
"name": o,
|
||||
"destination": $dest: SceneProtocol.PortalDestination,
|
||||
"position": $targetPosition: Shapes.Vector3,
|
||||
"position": $targetPosition: Shapes.LiteralVector3,
|
||||
}) => {
|
||||
const newPos = new Vector3(targetPosition.x,
|
||||
targetPosition.y,
|
||||
|
@ -169,29 +172,46 @@ async function enterScene(
|
|||
}
|
||||
}
|
||||
|
||||
assert Shapes.Sprite({
|
||||
const _POS = Symbol.for('pos');
|
||||
const _HEAD = Symbol.for('head');
|
||||
const _BODY = Symbol.for('body');
|
||||
|
||||
assert Shapes.Variable({ spriteName: id, variable: _POS, value: Shapes.fromImmediateVector3(position.value) });
|
||||
assert Shapes.Variable({ spriteName: id, variable: _HEAD, value: Shapes.fromImmediateVector3(rotation.value) });
|
||||
assert Shapes.Variable({ spriteName: id, variable: _BODY, value: Shapes.fromImmediateVector3({
|
||||
x: Shapes.DoubleValue.immediate(0),
|
||||
y: rotation.value.y,
|
||||
z: Shapes.DoubleValue.immediate(0),
|
||||
}) });
|
||||
|
||||
assert (() => {
|
||||
const s = Shapes.Sprite({
|
||||
name: id,
|
||||
formals: [_POS, _HEAD, _BODY],
|
||||
shape: B.nonphysical(
|
||||
B.move(position.value, B.many([
|
||||
B.move({ x: 0, y: -0.9, z: 0 },
|
||||
B.rotate(scale3({ x: 0, y: rotation.value.y, z: 0 }, 1 / (2 * Math.PI)),
|
||||
B.scale({ x: 0.4, y: 1.4, z: 0.1 }, B.box()))),
|
||||
B.rotate(scale3(rotation.value, 1 / (2 * Math.PI)),
|
||||
B.scale({ x: 0.15, y: 0.23, z: 0.18 }, B.many([
|
||||
B.move(Shapes.Vector3.reference(_POS), B.many([
|
||||
B.move(u3v({x: 0, y: -0.9, z: 0}),
|
||||
B.rotate(Shapes.Vector3.reference(_BODY),
|
||||
B.scale(u3v({x: 0.4, y: 1.4, z: 0.1}), B.box()))),
|
||||
B.rotate(Shapes.Vector3.reference(_HEAD),
|
||||
B.scale(u3v({x: 0.15, y: 0.23, z: 0.18}), B.many([
|
||||
B.box(),
|
||||
B.move({ x: 0, y: 0, z: 0.501 },
|
||||
B.move(u3v({x: 0, y: 0, z: 0.501}),
|
||||
B.texture(
|
||||
Shapes.TextureSpec.uvAlpha({
|
||||
path: `https://www.gravatar.com/avatar/${md5(new TextEncoder().encode(email.value.trim()))}?s=256&d=wavatar`,
|
||||
scale: Shapes.Vector2({ x:1, y:1 }),
|
||||
offset: Shapes.Vector2({ x:0, y:0 }),
|
||||
alpha: 1
|
||||
scale: Shapes.Vector2.immediate(u2({ x:1, y:1 })),
|
||||
offset: Shapes.Vector2.immediate(u2({ x:0, y:0 })),
|
||||
alpha: Shapes.DoubleValue.immediate(1),
|
||||
}),
|
||||
B.rotate({ x: 0, y: 0.5, z: 0 },
|
||||
B.rotate(u3v({ x: 0, y: 0.5, z: 0 }),
|
||||
B.plane()))),
|
||||
]))),
|
||||
]))),
|
||||
});
|
||||
});
|
||||
console.log(s);
|
||||
return s;
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +285,7 @@ window.addEventListener('load', async () => {
|
|||
Dataspace.boot(ds => {
|
||||
html.boot(ds);
|
||||
timer.boot(ds);
|
||||
wsRelay.boot(ds, false);
|
||||
wsRelay.boot(ds, true);
|
||||
wakeDetector.boot(ds);
|
||||
bootApp(ds, runningEngine);
|
||||
});
|
||||
|
|
213
src/shapes.ts
213
src/shapes.ts
|
@ -20,10 +20,46 @@ import {
|
|||
Vector2,
|
||||
Vector3,
|
||||
} from '@babylonjs/core/Legacy/legacy';
|
||||
import { KeyedDictionary, Value, is } from "@syndicate-lang/core";
|
||||
import { Dataflow, IdentityMap, KeyedDictionary, Ref, Value, is } from "@syndicate-lang/core";
|
||||
|
||||
import * as Shapes from './gen/shapes.js';
|
||||
|
||||
export class Environment {
|
||||
fields = new IdentityMap<symbol, Dataflow.Field<Value<Ref>>>();
|
||||
|
||||
constructor(
|
||||
public spriteName: string,
|
||||
public formals: symbol[],
|
||||
public sceneDs: Ref,
|
||||
) {
|
||||
formals.forEach(f => {
|
||||
field v: Value<Ref> = false;
|
||||
at this.sceneDs {
|
||||
on asserted Shapes.Variable({
|
||||
"spriteName": this.spriteName,
|
||||
"variable": f,
|
||||
"value": $newValue,
|
||||
}) => {
|
||||
console.log('Got value for', spriteName, f, newValue);
|
||||
v.value = newValue;
|
||||
}
|
||||
}
|
||||
this.fields.set(f, v);
|
||||
});
|
||||
}
|
||||
|
||||
lookup(f: symbol, k: (v: Value<Ref>) => void) {
|
||||
dataflow {
|
||||
const v = this.fields.get(f);
|
||||
if (v === void 0) throw new Error(`Lookup of ${f.description} in ${this.spriteName} failed`);
|
||||
const w = v.value;
|
||||
if (w !== false) k(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type ValueK = (v: Value<Ref>) => void;
|
||||
|
||||
export const activeFloorMeshes: Array<AbstractMesh> = [];
|
||||
export const activeTouchableMeshes: Array<AbstractMesh> = [];
|
||||
|
||||
|
@ -50,13 +86,13 @@ export class ShapeTree<N extends Node = Node> {
|
|||
return this.subnodes.then(ns => [this.rootnode, ... ns]);
|
||||
}
|
||||
|
||||
reconcile(spriteName: string, name: string, shape: Shapes.Shape): ShapeTree {
|
||||
reconcile(env: Environment, name: string, shape: Shapes.Shape): ShapeTree {
|
||||
if (is(Shapes.fromShape(shape), this.shapePreserve)) {
|
||||
return this;
|
||||
} else {
|
||||
this.remove();
|
||||
return build(name, this.scene, shape, {
|
||||
spriteName: async m => m.rootnode.metadata.spriteName = spriteName,
|
||||
return build(env, name, this.scene, shape, {
|
||||
spriteName: async m => m.rootnode.metadata.spriteName = env.spriteName,
|
||||
collisions: async m => (await m.allnodes).forEach(n => n.checkCollisions = true),
|
||||
});
|
||||
}
|
||||
|
@ -82,20 +118,64 @@ export class ShapeTree<N extends Node = Node> {
|
|||
}
|
||||
}
|
||||
|
||||
export function v2(v: Shapes.Vector2): Vector2 {
|
||||
return new Vector2(v.x, v.y);
|
||||
export function dv(env: Environment, v: Shapes.DoubleValue, k: (v: number) => void) {
|
||||
switch (v._variant) {
|
||||
case "immediate": k(v.value); break;
|
||||
case "reference": env.lookup(v.value, k as ValueK); break;
|
||||
}
|
||||
}
|
||||
|
||||
export function v3(v: Shapes.Vector3): Vector3 {
|
||||
return new Vector3(v.x, v.y, v.z);
|
||||
export function u2(v: {x: number, y: number}): Shapes.ImmediateVector2 {
|
||||
return Shapes.ImmediateVector2({
|
||||
x: Shapes.DoubleValue.immediate(v.x),
|
||||
y: Shapes.DoubleValue.immediate(v.y),
|
||||
});
|
||||
}
|
||||
|
||||
export function scale3(v: Shapes.Vector3, scale: number): Shapes.Vector3 {
|
||||
return Shapes.Vector3({ x: v.x * scale, y: v.y * scale, z: v.z * scale });
|
||||
export function lv2(env: Environment, v: Shapes.ImmediateVector2, k: (v: Vector2) => void) {
|
||||
dv(env, v.x, x => dv(env, v.y, y => k(new Vector2(x, y))));
|
||||
}
|
||||
|
||||
export function q(q: Shapes.Quaternion): Quaternion {
|
||||
return new Quaternion(q.a, q.b, q.c, q.d);
|
||||
export function v2(env: Environment, v: Shapes.Vector2, k: (v: Vector2) => void) {
|
||||
switch (v._variant) {
|
||||
case "immediate": lv2(env, v.value, k); break;
|
||||
case "reference": env.lookup(v.value, v => lv2(env, Shapes.asImmediateVector2(v), k)); break;
|
||||
}
|
||||
}
|
||||
|
||||
export function u3(v: {x: number, y: number, z: number}, scale = 1): Shapes.ImmediateVector3 {
|
||||
return Shapes.ImmediateVector3({
|
||||
x: Shapes.DoubleValue.immediate(v.x * scale),
|
||||
y: Shapes.DoubleValue.immediate(v.y * scale),
|
||||
z: Shapes.DoubleValue.immediate(v.z * scale),
|
||||
});
|
||||
}
|
||||
|
||||
export function u3v(v: {x: number, y: number, z: number}, scale = 1): Shapes.Vector3 {
|
||||
return Shapes.Vector3.immediate(u3(v, scale));
|
||||
}
|
||||
|
||||
export function lv3(env: Environment, v: Shapes.ImmediateVector3, k: (v: Vector3) => void) {
|
||||
dv(env, v.x, x => dv(env, v.y, y => dv(env, v.z, z => k(new Vector3(x, y, z)))));
|
||||
}
|
||||
|
||||
export function v3(env: Environment, v: Shapes.Vector3, k: (v: Vector3) => void) {
|
||||
switch (v._variant) {
|
||||
case "immediate": lv3(env, v.value, k); break;
|
||||
case "reference": env.lookup(v.value, v => lv3(env, Shapes.asImmediateVector3(v), k)); break;
|
||||
}
|
||||
}
|
||||
|
||||
export function lq(env: Environment, q: Shapes.ImmediateQuaternion, k: (v: Quaternion) => void) {
|
||||
dv(env, q.a, a => dv(env, q.b, b => dv(env, q.c, c => dv(env, q.d, d =>
|
||||
k(new Quaternion(a, b, c, d))))));
|
||||
}
|
||||
|
||||
export function q(env: Environment, q: Shapes.Quaternion, k: (v: Quaternion) => void) {
|
||||
switch (q._variant) {
|
||||
case "immediate": lq(env, q.value, k); break;
|
||||
case "reference": env.lookup(q.value, q => lq(env, Shapes.asImmediateQuaternion(q), k)); break;
|
||||
}
|
||||
}
|
||||
|
||||
export type MeshCustomizer = { [key: string]: ((m: ShapeTree<AbstractMesh>) => void) };
|
||||
|
@ -111,7 +191,7 @@ type CachedTexture = {
|
|||
};
|
||||
const textureCache = new KeyedDictionary<Value, CachedTexture>();
|
||||
|
||||
function buildTexture(name: string, scene: Scene, spec: Shapes.TextureSpec): CachedTexture {
|
||||
function buildTexture(env: Environment, name: string, scene: Scene, spec: Shapes.TextureSpec): CachedTexture {
|
||||
const cacheKey = Shapes.fromTextureSpec(spec);
|
||||
const entry = textureCache.get(cacheKey);
|
||||
if (entry !== void 0) {
|
||||
|
@ -125,18 +205,18 @@ function buildTexture(name: string, scene: Scene, spec: Shapes.TextureSpec): Cac
|
|||
case "simple":
|
||||
break;
|
||||
case "uvAlpha":
|
||||
mat.alpha = spec.alpha;
|
||||
mat.alpha = 0;
|
||||
dv(env, spec.alpha, a => mat.alpha = a);
|
||||
tex.hasAlpha = true;
|
||||
/* FALL THROUGH */
|
||||
case "uv": {
|
||||
const scale = v2(spec.scale);
|
||||
const offset = v2(spec.offset);
|
||||
tex.uScale = scale.x;
|
||||
tex.vScale = scale.y;
|
||||
tex.uOffset = offset.x;
|
||||
tex.vOffset = offset.y;
|
||||
case "uv":
|
||||
v2(env, spec.scale, scale => v2(env, spec.offset, offset => {
|
||||
tex.uScale = scale.x;
|
||||
tex.vScale = scale.y;
|
||||
tex.uOffset = offset.x;
|
||||
tex.vOffset = offset.y;
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
const newEntry = {
|
||||
key: cacheKey,
|
||||
|
@ -167,13 +247,7 @@ export function buildMesh(
|
|||
switch (meshSpec._variant) {
|
||||
case "Sphere": return { rootnode: MeshBuilder.CreateSphere(name, {}, scene) };
|
||||
case "Box": return { rootnode: MeshBuilder.CreateBox(name, {}, scene) };
|
||||
case "Ground": {
|
||||
const v = v2(meshSpec.value.size);
|
||||
return {
|
||||
rootnode: MeshBuilder.CreateGround(
|
||||
name, { width: v.x, height: v.y }, scene ?? void 0),
|
||||
};
|
||||
}
|
||||
case "Ground": return { rootnode: MeshBuilder.CreateGround(name, {}, scene ?? void 0) };
|
||||
case "Plane": return { rootnode: MeshBuilder.CreatePlane(name, {}, scene) };
|
||||
case "External": {
|
||||
const rootnode = new Mesh(name, scene);
|
||||
|
@ -210,7 +284,7 @@ export function buildSound(name: string, scene: Scene, spec: Shapes.SoundSpec, s
|
|||
return new Sound(name, spec.url, scene, null, options);
|
||||
}
|
||||
|
||||
export function build(name: string, scene: Scene, shape: Shapes.Shape, customize: MeshCustomizer): ShapeTree {
|
||||
export function build(env: Environment, name: string, scene: Scene, shape: Shapes.Shape, customize: MeshCustomizer): ShapeTree {
|
||||
switch (shape._variant) {
|
||||
case "Mesh": {
|
||||
const m = buildMesh(name, scene, shape.value);
|
||||
|
@ -219,23 +293,23 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
return t;
|
||||
}
|
||||
|
||||
case "Light":
|
||||
return new ShapeTree(
|
||||
scene,
|
||||
shape,
|
||||
new HemisphericLight(name, v3(shape.value.v), scene));
|
||||
case "Light": {
|
||||
const light = new HemisphericLight(name, new Vector3(0, 1, 0), scene);
|
||||
v3(env, shape.value.v, v => light.direction = v);
|
||||
return new ShapeTree(scene, shape, light);
|
||||
}
|
||||
|
||||
case "Scale": {
|
||||
const t = ShapeTree.transform(name, scene, shape);
|
||||
t.rootnode.scaling = v3(shape.value.v);
|
||||
build(name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
v3(env, shape.value.v, v => t.rootnode.scaling = v);
|
||||
build(env, name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
case "Move": {
|
||||
const t = ShapeTree.transform(name, scene, shape);
|
||||
t.rootnode.position = v3(shape.value.v);
|
||||
build(name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
v3(env, shape.value.v, v => t.rootnode.position = v);
|
||||
build(env, name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -243,28 +317,30 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
const t = ShapeTree.transform(name, scene, shape);
|
||||
switch (shape.value._variant) {
|
||||
case "euler":
|
||||
t.rootnode.rotation = v3(shape.value.v);
|
||||
t.rootnode.rotation.scaleInPlace(2 * Math.PI);
|
||||
v3(env, shape.value.v, v => {
|
||||
t.rootnode.rotation = v;
|
||||
t.rootnode.rotation.scaleInPlace(2 * Math.PI);
|
||||
});
|
||||
break;
|
||||
case "quaternion":
|
||||
t.rootnode.rotationQuaternion = q(shape.value.q);
|
||||
q(env, shape.value.q, q => t.rootnode.rotationQuaternion = q);
|
||||
break;
|
||||
}
|
||||
build(name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
build(env, name + '.inner', scene, shape.value.shape, customize).parent = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
case "many": {
|
||||
const t = ShapeTree.transform(name, scene, shape);
|
||||
shape.value.forEach((s, i) => {
|
||||
build(name + '[' + i + ']', scene, s, customize).parent = t;
|
||||
build(env, name + '[' + i + ']', scene, s, customize).parent = t;
|
||||
});
|
||||
return t;
|
||||
}
|
||||
|
||||
case "Texture": {
|
||||
const entry = buildTexture(name + '.texture', scene, shape.value.spec);
|
||||
const t = build(name + '.inner', scene, shape.value.shape, {
|
||||
const entry = buildTexture(env, name + '.texture', scene, shape.value.spec);
|
||||
const t = build(env, name + '.inner', scene, shape.value.shape, {
|
||||
... customize,
|
||||
material: async m => (await m.allnodes).forEach(n => n.material = entry.material),
|
||||
});
|
||||
|
@ -274,9 +350,13 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
|
||||
case "Color": {
|
||||
const mat = new StandardMaterial(name + '.texture', scene);
|
||||
mat.diffuseColor = new Color3(shape.value.r, shape.value.g, shape.value.b);
|
||||
if (shape.value._variant === "transparent") mat.alpha = shape.value.alpha;
|
||||
const t = build(name + '.inner', scene, shape.value.shape, {
|
||||
dv(env, shape.value.r, r =>
|
||||
dv(env, shape.value.g, g =>
|
||||
dv(env, shape.value.b, b => mat.diffuseColor = new Color3(r, g, b))));
|
||||
if (shape.value._variant === "transparent") {
|
||||
dv(env, shape.value.alpha, a => mat.alpha = a);
|
||||
}
|
||||
const t = build(env, name + '.inner', scene, shape.value.shape, {
|
||||
... customize,
|
||||
material: async m => (await m.allnodes).forEach(n => n.material = mat),
|
||||
});
|
||||
|
@ -286,7 +366,7 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
|
||||
case "Sound": {
|
||||
const sound = buildSound(name + ".sound", scene, shape.value.spec, true);
|
||||
const t = build(name + ".inner", scene, shape.value.shape, {
|
||||
const t = build(env, name + ".inner", scene, shape.value.shape, {
|
||||
... customize,
|
||||
sound: async m => sound.attachToMesh(m.rootnode),
|
||||
});
|
||||
|
@ -295,10 +375,10 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
}
|
||||
|
||||
case "Name":
|
||||
return build(name + '.' + shape.value.base, scene, shape.value.shape, customize);
|
||||
return build(env, name + '.' + shape.value.base, scene, shape.value.shape, customize);
|
||||
|
||||
case "Floor":
|
||||
return build(name, scene, shape.value.shape, {
|
||||
return build(env, name, scene, shape.value.shape, {
|
||||
... customize,
|
||||
floor: async m => {
|
||||
const nodes = await m.allnodes;
|
||||
|
@ -311,13 +391,13 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
|
|||
});
|
||||
|
||||
case "Nonphysical":
|
||||
return build(name, scene, shape.value.shape, {
|
||||
return build(env, name, scene, shape.value.shape, {
|
||||
... customize,
|
||||
collisions: async m => (await m.allnodes).forEach(n => n.checkCollisions = false),
|
||||
});
|
||||
|
||||
case "Touchable":
|
||||
return build(name, scene, shape.value.shape, {
|
||||
return build(env, name, scene, shape.value.shape, {
|
||||
... customize,
|
||||
touchable: async m => {
|
||||
const nodes = await m.allnodes;
|
||||
|
@ -426,23 +506,30 @@ export function buildCSG(name: string, scene: Scene, expr: Shapes.CSGExpr): Buil
|
|||
};
|
||||
}
|
||||
|
||||
export const builder: { [key: string]: (... args: any[]) => Shapes.Shape } = {
|
||||
export const builder = {
|
||||
sphere: () => Shapes.Shape.Mesh(Shapes.Mesh.Sphere(Shapes.Sphere())),
|
||||
box: () => Shapes.Shape.Mesh(Shapes.Mesh.Box(Shapes.Box())),
|
||||
plane: () => Shapes.Shape.Mesh(Shapes.Mesh.Plane(Shapes.Plane())),
|
||||
ground: (v: Shapes.Vector2) => Shapes.Shape.Mesh(Shapes.Mesh.Ground(Shapes.Ground(Shapes.Vector2(v)))),
|
||||
light: (v: Shapes.Vector3) => Shapes.Shape.Light(Shapes.Light(Shapes.Vector3(v))),
|
||||
scale: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Scale(Shapes.Scale({ v: Shapes.Vector3(v), shape })),
|
||||
move: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Move(Shapes.Move({ v: Shapes.Vector3(v), shape })),
|
||||
rotate: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Rotate(Shapes.Rotate.euler({ v: Shapes.Vector3(v), shape })),
|
||||
ground: () => Shapes.Shape.Mesh(Shapes.Mesh.Ground(Shapes.Ground())),
|
||||
light: (v: Shapes.Vector3) => Shapes.Shape.Light(Shapes.Light(v)),
|
||||
scale: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Scale(Shapes.Scale({ v, shape })),
|
||||
move: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Move(Shapes.Move({ v, shape })),
|
||||
rotate: (v: Shapes.Vector3, shape: Shapes.Shape) => Shapes.Shape.Rotate(Shapes.Rotate.euler({ v, shape })),
|
||||
many: (shapes: Shapes.Shape[]) => Shapes.Shape.many(shapes),
|
||||
texture: (spec: Shapes.TextureSpec, shape: Shapes.Shape) => Shapes.Shape.Texture(Shapes.Texture({ spec, shape })),
|
||||
color: (r: number, g: number, b: number, shape: Shapes.Shape, alpha = 1.0) => {
|
||||
return Shapes.Shape.Color((alpha === 1.0)
|
||||
color: (r0: number | symbol, g0: number | symbol, b0: number | symbol, shape: Shapes.Shape, alpha0: number | symbol = 1.0) => {
|
||||
function vd(x: number | symbol): Shapes.DoubleValue {
|
||||
return typeof x === 'number' ? Shapes.DoubleValue.immediate(x) : Shapes.DoubleValue.reference(x);
|
||||
}
|
||||
const r = vd(r0);
|
||||
const g = vd(g0);
|
||||
const b = vd(b0);
|
||||
const alpha = vd(alpha0);
|
||||
return Shapes.Shape.Color((alpha0 === 1.0)
|
||||
? Shapes.Color.opaque({ r, g, b, shape })
|
||||
: Shapes.Color.transparent({ r, g, b, alpha, shape }));
|
||||
},
|
||||
name: (base: string, shape: Shapes.Shape) => Shapes.Shape.Name(Shapes.Name({ base, shape })),
|
||||
floor: (shape: Shapes.Shape) => Shapes.Shape.Floor(Shapes.Floor(shape)),
|
||||
nonphysical: (shape: Shapes.Shape) => Shapes.Shape.Nonphysical(Shapes.Nonphysical(shape)),
|
||||
};
|
||||
} satisfies { [key: string]: (... args: any[]) => Shapes.Shape };
|
||||
|
|
Loading…
Reference in New Issue