]> gitweb.factorcode.org Git - factor.git/blob - extra/benchmark/raytracer/raytracer.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / extra / benchmark / raytracer / raytracer.factor
1 ! Factor port of the raytracer benchmark from
2 ! http://www.ffconsultancy.com/free/ray_tracer/languages.html
3
4 USING: arrays accessors specialized-arrays.double io io.files
5 io.encodings.binary kernel math math.functions math.vectors
6 math.parser make sequences sequences.private words hints ;
7 IN: benchmark.raytracer
8
9 ! parameters
10 : light
11     #! Normalized { -1 -3 2 }.
12     double-array{
13         -0.2672612419124244
14         -0.8017837257372732
15         0.5345224838248488
16     } ; inline
17
18 : oversampling 4 ; inline
19
20 : levels 3 ; inline
21
22 : size 200 ; inline
23
24 : delta 1.4901161193847656E-8 ; inline
25
26 TUPLE: ray { orig double-array read-only } { dir double-array read-only } ;
27
28 C: <ray> ray
29
30 TUPLE: hit { normal double-array read-only } { lambda float read-only } ;
31
32 C: <hit> hit
33
34 GENERIC: intersect-scene ( hit ray scene -- hit )
35
36 TUPLE: sphere { center double-array read-only } { radius float read-only } ;
37
38 C: <sphere> sphere
39
40 : sphere-v ( sphere ray -- v )
41     [ center>> ] [ orig>> ] bi* v- ; inline
42
43 : sphere-b ( v ray -- b )
44     dir>> v. ; inline
45
46 : sphere-d ( sphere b v -- d )
47     [ radius>> sq ] [ sq ] [ norm-sq ] tri* - + ; inline
48
49 : -+ ( x y -- x-y x+y )
50     [ - ] [ + ] 2bi ; inline
51
52 : sphere-t ( b d -- t )
53     -+ dup 0.0 <
54     [ 2drop 1.0/0.0 ] [ [ [ 0.0 > ] keep ] dip ? ] if ; inline
55
56 : sphere-b&v ( sphere ray -- b v )
57     [ sphere-v ] [ nip ] 2bi
58     [ sphere-b ] [ drop ] 2bi ; inline
59
60 : ray-sphere ( sphere ray -- t )
61     [ drop ] [ sphere-b&v ] 2bi
62     [ drop ] [ sphere-d ] 3bi
63     dup 0.0 < [ 3drop 1/0. ] [ sqrt sphere-t nip ] if ; inline
64
65 : if-ray-sphere ( hit ray sphere quot -- hit )
66     #! quot: hit ray sphere l -- hit
67     [
68         [ ] [ swap ray-sphere nip ] [ 2drop lambda>> ] 3tri
69         [ drop ] [ < ] 2bi
70     ] dip [ 3drop ] if ; inline
71
72 : sphere-n ( ray sphere l -- n )
73     [ [ orig>> ] [ dir>> ] bi ] [ center>> ] [ ] tri*
74     swap [ v*n ] dip v- v+ ; inline
75
76 M: sphere intersect-scene ( hit ray sphere -- hit )
77     [ [ sphere-n normalize ] keep <hit> nip ] if-ray-sphere ;
78
79 TUPLE: group < sphere { objs array read-only } ;
80
81 : <group> ( objs bound -- group )
82     [ center>> ] [ radius>> ] bi rot group boa ; inline
83
84 : make-group ( bound quot -- )
85     swap [ { } make ] dip <group> ; inline
86
87 M: group intersect-scene ( hit ray group -- hit )
88     [ drop objs>> [ intersect-scene ] with each ] if-ray-sphere ;
89
90 : initial-hit T{ hit f double-array{ 0.0 0.0 0.0 } 1/0. } ; inline
91
92 : initial-intersect ( ray scene -- hit )
93     [ initial-hit ] 2dip intersect-scene ; inline
94
95 : ray-o ( ray hit -- o )
96     [ [ orig>> ] [ normal>> delta v*n ] bi* ]
97     [ [ dir>> ] [ lambda>> ] bi* v*n ]
98     2bi v+ v+ ; inline
99
100 : sray-intersect ( ray scene hit -- ray )
101     swap [ ray-o light vneg <ray> ] dip initial-intersect ; inline
102
103 : ray-g ( hit -- g ) normal>> light v. ; inline
104
105 : cast-ray ( ray scene -- g )
106     2dup initial-intersect dup lambda>> 1/0. = [
107         3drop 0.0
108     ] [
109         [ sray-intersect lambda>> 1/0. = ] keep swap
110         [ ray-g neg ] [ drop 0.0 ] if
111     ] if ; inline
112
113 : create-center ( c r d -- c2 )
114     [ 3.0 12.0 sqrt / * ] dip n*v v+ ; inline
115
116 DEFER: create ( level c r -- scene )
117
118 : create-step ( level c r d -- scene )
119     over [ create-center ] dip 2.0 / [ 1 - ] 2dip create ;
120
121 : create-offsets ( quot -- )
122     {
123         double-array{ -1.0 1.0 -1.0 }
124         double-array{ 1.0 1.0 -1.0 }
125         double-array{ -1.0 1.0 1.0 }
126         double-array{ 1.0 1.0 1.0 }
127     } swap each ; inline
128
129 : create-bound ( c r -- sphere ) 3.0 * <sphere> ;
130
131 : create-group ( level c r -- scene )
132     2dup create-bound [
133         2dup <sphere> ,
134         [ [ 3dup ] dip create-step , ] create-offsets 3drop
135     ] make-group ;
136
137 : create ( level c r -- scene )
138     pick 1 = [ <sphere> nip ] [ create-group ] if ;
139
140 : ss-point ( dx dy -- point )
141     [ oversampling /f ] bi@ 0.0 double-array{ } 3sequence ;
142
143 : ss-grid ( -- ss-grid )
144     oversampling [ oversampling [ ss-point ] with map ] map ;
145
146 : ray-grid ( point ss-grid -- ray-grid )
147     [
148         [ v+ normalize double-array{ 0.0 0.0 -4.0 } swap <ray> ] with map
149     ] with map ;
150
151 : ray-pixel ( scene point -- n )
152     ss-grid ray-grid 0.0 -rot
153     [ [ swap cast-ray + ] with each ] with each ;
154
155 : pixel-grid ( -- grid )
156     size reverse [
157         size [
158             [ size 0.5 * - ] bi@ swap size
159             double-array{ } 3sequence
160         ] with map
161     ] map ;
162
163 : pgm-header ( w h -- )
164     "P5\n" % swap # " " % # "\n255\n" % ;
165
166 : pgm-pixel ( n -- ) 255 * 0.5 + >fixnum , ;
167
168 : ray-trace ( scene -- pixels )
169     pixel-grid [ [ ray-pixel ] with map ] with map ;
170
171 : run ( -- string )
172     levels double-array{ 0.0 -1.0 0.0 } 1.0 create ray-trace [
173         size size pgm-header
174         [ [ oversampling sq / pgm-pixel ] each ] each
175     ] B{ } make ;
176
177 : raytracer-main ( -- )
178     run "raytracer.pnm" temp-file binary set-file-contents ;
179
180 MAIN: raytracer-main