1 ! Copyright (C) 2007 Alex Chapman
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays combinators float-arrays kernel jamshred.oint locals math math.functions math.constants math.matrices math.order math.ranges math.vectors math.quadratic random sequences vectors ;
6 : n-segments ( -- n ) 5000 ; inline
8 TUPLE: segment < oint number color radius ;
11 : segment-vertex ( theta segment -- vertex )
12 tuck 2dup up>> swap sin v*n
13 >r left>> swap cos v*n r> v+
16 : segment-vertex-normal ( vertex segment -- normal )
17 location>> swap v- normalize ;
19 : segment-vertex-and-normal ( segment theta -- vertex normal )
20 swap [ segment-vertex ] keep dupd segment-vertex-normal ;
22 : equally-spaced-radians ( n -- seq )
23 #! return a sequence of n numbers between 0 and 2pi
24 dup [ / pi 2 * * ] curry map ;
26 : segment-number++ ( segment -- )
27 [ number>> 1+ ] keep (>>number) ;
29 : random-color ( -- color )
30 { 100 100 100 } [ random 100 / >float ] map { 1.0 } append ;
32 : tunnel-segment-distance ( -- n ) 0.4 ;
33 : random-rotation-angle ( -- theta ) pi 20 / ;
35 : random-segment ( previous-segment -- segment )
36 clone dup random-rotation-angle random-turn
37 tunnel-segment-distance over go-forward
38 random-color over set-segment-color dup segment-number++ ;
40 : (random-segments) ( segments n -- segments )
42 >r dup peek random-segment over push r> 1- (random-segments)
47 : default-segment-radius ( -- r ) 1 ;
49 : initial-segment ( -- segment )
50 F{ 0 0 0 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 }
51 0 random-color default-segment-radius <segment> ;
53 : random-segments ( n -- segments )
54 initial-segment 1vector swap (random-segments) ;
56 : simple-segment ( n -- segment )
57 [ F{ 0 0 -1 } n*v F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] keep
58 random-color default-segment-radius <segment> ;
60 : simple-segments ( n -- segments )
61 [ simple-segment ] map ;
63 : <random-tunnel> ( -- segments )
64 n-segments random-segments ;
66 : <straight-tunnel> ( -- segments )
67 n-segments simple-segments ;
69 : sub-tunnel ( from to sements -- segments )
70 #! return segments between from and to, after clamping from and to to
72 [ sequence-index-range [ clamp-to-range ] curry bi@ ] keep <slice> ;
74 : nearer-segment ( segment segment oint -- segment )
75 #! return whichever of the two segments is nearer to the oint
76 >r 2dup r> tuck distance >r distance r> < -rot ? ;
78 : (find-nearest-segment) ( nearest next oint -- nearest ? )
79 #! find the nearest of 'next' and 'nearest' to 'oint', and return
80 #! t if the nearest hasn't changed
81 pick >r nearer-segment dup r> = ;
83 : find-nearest-segment ( oint segments -- segment )
84 dup first swap rest-slice rot [ (find-nearest-segment) ] curry
87 : nearest-segment-forward ( segments oint start -- segment )
88 rot dup length swap <slice> find-nearest-segment ;
90 : nearest-segment-backward ( segments oint start -- segment )
91 swapd 1+ 0 spin <slice> <reversed> find-nearest-segment ;
93 : nearest-segment ( segments oint start-segment -- segment )
94 #! find the segment nearest to 'oint', and return it.
95 #! start looking at segment 'start-segment'
96 segment-number over >r
97 [ nearest-segment-forward ] 3keep
98 nearest-segment-backward r> nearer-segment ;
100 : vector-to-centre ( seg loc -- v )
101 over location>> swap v- swap forward>> proj-perp ;
103 : distance-from-centre ( seg loc -- distance )
104 vector-to-centre norm ;
106 : wall-normal ( seg oint -- n )
107 location>> vector-to-centre normalize ;
109 : from ( seg loc -- radius d-f-c )
110 dupd location>> distance-from-centre [ radius>> ] dip ;
112 : distance-from-wall ( seg loc -- distance ) from - ;
113 : fraction-from-centre ( seg loc -- fraction ) from / ;
114 : fraction-from-wall ( seg loc -- fraction )
115 fraction-from-centre 1 swap - ;
117 :: collision-coefficient ( v w r -- c )
118 [let* | a [ v dup v. ]
120 c [ w dup v. r sq - ] |
121 c b a quadratic max ] ;
123 : sideways-heading ( oint segment -- v )
124 [ forward>> ] bi@ proj-perp ;
126 : sideways-relative-location ( oint segment -- loc )
127 [ [ location>> ] bi@ v- ] keep forward>> proj-perp ;
129 : bounce-offset 0.1 ; inline
131 : bounce-radius ( segment -- r )
132 radius>> bounce-offset - ; ! bounce before we hit so that we can't see through the wall (hack?)
134 : collision-vector ( oint segment -- v )
135 [ sideways-heading ] [ sideways-relative-location ]
136 [ bounce-radius ] 2tri
137 swap [ collision-coefficient ] dip forward>> n*v ;
139 : distance-to-collision ( oint segment -- distance )
140 collision-vector norm ;
142 : bounce-forward ( segment oint -- )
143 [ wall-normal ] [ forward>> swap reflect ] [ (>>forward) ] tri ;
145 : bounce-left ( segment oint -- )
146 #! must be done after forward
147 [ forward>> vneg ] dip [ left>> swap reflect ]
148 [ forward>> proj-perp normalize ] [ (>>left) ] tri ;
150 : bounce-up ( segment oint -- )
151 #! must be done after forward and left!
152 nip [ forward>> ] [ left>> cross ] [ (>>up) ] tri ;
154 : bounce ( oint segment -- )
155 swap [ bounce-forward ] [ bounce-left ] [ bounce-up ] 2tri ;