]> gitweb.factorcode.org Git - factor.git/blob - extra/gpu/demos/bunny/bunny.factor
Merge branch 'master' into simd-cleanup
[factor.git] / extra / gpu / demos / bunny / bunny.factor
1 ! (c)2009 Joe Groff bsd license
2 USING: accessors alien.c-types arrays classes.struct combinators
3 combinators.short-circuit game.worlds gpu gpu.buffers
4 gpu.util.wasd gpu.framebuffers gpu.render gpu.shaders gpu.state
5 gpu.textures gpu.util grouping http.client images images.loader
6 io io.encodings.ascii io.files io.files.temp kernel locals math
7 math.matrices math.vectors.simd math.parser math.vectors
8 method-chains namespaces sequences splitting threads ui ui.gadgets
9 ui.gadgets.worlds ui.pixel-formats specialized-arrays
10 specialized-vectors ;
11 FROM: alien.c-types => float ;
12 SPECIALIZED-ARRAY: float
13 SPECIALIZED-VECTOR: uint
14 IN: gpu.demos.bunny
15
16 GLSL-SHADER-FILE: bunny-vertex-shader vertex-shader "bunny.v.glsl"
17 GLSL-SHADER-FILE: bunny-fragment-shader fragment-shader "bunny.f.glsl"
18 GLSL-PROGRAM: bunny-program
19     bunny-vertex-shader bunny-fragment-shader ;
20
21 GLSL-SHADER-FILE: window-vertex-shader vertex-shader "window.v.glsl"
22
23 GLSL-SHADER-FILE: sobel-fragment-shader fragment-shader "sobel.f.glsl"
24 GLSL-PROGRAM: sobel-program
25     window-vertex-shader sobel-fragment-shader ;
26
27 GLSL-SHADER-FILE: loading-fragment-shader fragment-shader "loading.f.glsl"
28 GLSL-PROGRAM: loading-program
29     window-vertex-shader loading-fragment-shader ;
30
31 TUPLE: bunny-state
32     vertexes
33     indexes
34     vertex-array
35     index-elements ;
36
37 TUPLE: sobel-state
38     vertex-array
39     color-texture
40     normal-texture
41     depth-texture
42     framebuffer ;
43
44 TUPLE: loading-state
45     vertex-array
46     texture ;
47
48 TUPLE: bunny-world < wasd-world
49     bunny sobel loading ;
50
51 VERTEX-FORMAT: bunny-vertex
52     { "vertex" float-components 3 f }
53     { f        float-components 1 f }
54     { "normal" float-components 3 f }
55     { f        float-components 1 f } ;
56
57 STRUCT: bunny-vertex-struct
58     { vertex float-4 }
59     { normal float-4 } ;
60
61 SPECIALIZED-VECTOR: bunny-vertex-struct
62
63 UNIFORM-TUPLE: bunny-uniforms < mvp-uniforms
64     { "light-position" vec3-uniform  f }
65     { "color"          vec4-uniform  f }
66     { "ambient"        vec4-uniform  f }
67     { "diffuse"        vec4-uniform  f }
68     { "shininess"      float-uniform f } ;
69
70 UNIFORM-TUPLE: sobel-uniforms
71     { "texcoord-scale" vec2-uniform    f }
72     { "color-texture"  texture-uniform f }
73     { "normal-texture" texture-uniform f }
74     { "depth-texture"  texture-uniform f }
75     { "line-color"     vec4-uniform    f } ; 
76
77 UNIFORM-TUPLE: loading-uniforms
78     { "texcoord-scale"  vec2-uniform    f }
79     { "loading-texture" texture-uniform f } ;
80
81 : numbers ( tokens -- seq )
82     [ string>number ] map ; inline
83
84 : <bunny-vertex> ( vertex -- struct )
85     bunny-vertex-struct <struct>
86         swap first3 0.0 float-4-boa >>vertex ; inline
87
88 : (read-line-tokens) ( seq stream -- seq )
89     " \n" over stream-read-until
90     [ [ pick push ] unless-empty ]
91     [
92         {
93             { CHAR: \s [ (read-line-tokens) ] }
94             { CHAR: \n [ drop ] }
95             [ 2drop [ f ] when-empty ]
96         } case
97     ] bi* ; inline recursive
98
99 : stream-read-line-tokens ( stream -- seq )
100     V{ } clone swap (read-line-tokens) ;
101
102 : each-line-tokens ( quot -- )
103     input-stream get [ stream-read-line-tokens ] curry each-morsel ; inline
104
105 : (parse-bunny-model) ( vs is -- vs is )
106     [
107         numbers {
108             { [ dup length 5 = ] [ <bunny-vertex> pick push ] }
109             { [ dup first 3 = ] [ rest append! ] }
110             [ drop ]
111         } cond
112     ] each-line-tokens ; inline
113
114 : parse-bunny-model ( -- vertexes indexes )
115     100000 <bunny-vertex-struct-vector>
116     100000 <uint-vector>
117     (parse-bunny-model) ; inline
118
119 :: normal ( a b c -- normal )
120     c a v-
121     b a v- cross normalize ; inline
122
123 :: calc-bunny-normal ( a b c vertexes -- )
124     a b c [ vertexes nth vertex>> ] tri@ normal :> n
125     a b c [ vertexes nth [ n v+ ] change-normal drop ] tri@ ; inline
126
127 : calc-bunny-normals ( vertexes indexes -- )
128     3 <sliced-groups> swap
129     [ [ first3 ] dip calc-bunny-normal ] curry each ; inline
130
131 : normalize-bunny-normals ( vertexes -- )
132     [ [ normalize ] change-normal drop ] each ; inline
133
134 : bunny-data ( filename -- vertexes indexes )
135     ascii [ parse-bunny-model ] with-file-reader
136     [ calc-bunny-normals ]
137     [ drop normalize-bunny-normals ]
138     [ ] 2tri ;
139
140 : <bunny-buffers> ( vertexes indexes -- vertex-buffer index-buffer index-count )
141     [ underlying>> static-upload draw-usage vertex-buffer byte-array>buffer ]
142     [
143         [ underlying>> static-upload draw-usage index-buffer  byte-array>buffer ]
144         [ length ] bi
145     ] bi* ;
146
147 : bunny-model-path ( -- path ) "bun_zipper.ply" temp-file ;
148
149 CONSTANT: bunny-model-url "http://factorcode.org/bun_zipper.ply"
150
151 : download-bunny ( -- path )
152     bunny-model-path dup exists? [
153         bunny-model-url dup print flush
154         over download-to
155     ] unless ;
156
157 : get-bunny-data ( bunny-state -- )
158     download-bunny bunny-data
159     [ >>vertexes ] [ >>indexes ] bi* drop ;
160
161 : fill-bunny-state ( bunny-state -- )
162     dup [ vertexes>> ] [ indexes>> ] bi <bunny-buffers>
163     [ bunny-program <program-instance> bunny-vertex buffer>vertex-array >>vertex-array ]
164     [ 0 <buffer-ptr> ]
165     [ uint-indexes <index-elements> >>index-elements ] tri*
166     drop ;
167
168 : <bunny-state> ( -- bunny-state )
169     bunny-state new
170     dup [ get-bunny-data ] curry "Downloading bunny model" spawn drop ;
171
172 : bunny-loaded? ( bunny-state -- ? )
173     { [ vertexes>> ] [ indexes>> ] } 1&& ;
174
175 : bunny-state-filled? ( bunny-state -- ? )
176     { [ vertex-array>> ] [ index-elements>> ] } 1&& ;
177
178 : <sobel-state> ( window-vertex-buffer -- sobel-state )
179     sobel-state new
180         swap sobel-program <program-instance> window-vertex buffer>vertex-array >>vertex-array
181
182         RGBA half-components T{ texture-parameters
183             { wrap clamp-texcoord-to-edge }
184             { min-filter filter-linear }
185             { min-mipmap-filter f }
186         } <texture-2d> >>color-texture
187         RGBA half-components T{ texture-parameters
188             { wrap clamp-texcoord-to-edge }
189             { min-filter filter-linear }
190             { min-mipmap-filter f }
191         } <texture-2d> >>normal-texture
192         DEPTH u-24-components T{ texture-parameters
193             { wrap clamp-texcoord-to-edge }
194             { min-filter filter-linear }
195             { min-mipmap-filter f }
196         } <texture-2d> >>depth-texture
197
198         dup
199         [
200             [ color-texture>>  0 <texture-2d-attachment> ]
201             [ normal-texture>> 0 <texture-2d-attachment> ] bi 2array
202         ] [ depth-texture>> 0 <texture-2d-attachment> ] bi f { 1024 768 } <framebuffer> >>framebuffer ;
203
204 : <loading-state> ( window-vertex-buffer -- loading-state )
205     loading-state new
206         swap
207         loading-program <program-instance> window-vertex buffer>vertex-array >>vertex-array
208
209         RGBA ubyte-components T{ texture-parameters
210             { wrap clamp-texcoord-to-edge }
211             { min-filter filter-linear }
212             { min-mipmap-filter f }
213         } <texture-2d>
214         dup 0 "vocab:gpu/demos/bunny/loading.tiff" load-image allocate-texture-image
215         >>texture ;
216
217 BEFORE: bunny-world begin-world
218     init-gpu
219     
220     { -0.2 0.13 0.1 } 1.1 0.2 set-wasd-view
221
222     <bunny-state> >>bunny
223     <window-vertex-buffer>
224     [ <sobel-state> >>sobel ]
225     [ <loading-state> >>loading ] bi
226     drop ;
227
228 : <bunny-uniforms> ( world -- uniforms )
229     [ wasd-mv-matrix ] [ wasd-p-matrix ] bi
230     { -10000.0 10000.0 10000.0 } ! light position
231     { 0.6 0.5 0.5 1.0 } ! color
232     { 0.2 0.2 0.2 0.2 } ! ambient
233     { 0.8 0.8 0.8 0.8 } ! diffuse
234     100.0 ! shininess
235     bunny-uniforms boa ;
236
237 : draw-bunny ( world -- )
238     T{ depth-state { comparison cmp-less } } set-gpu-state
239     
240     [
241         sobel>> framebuffer>> {
242             { T{ color-attachment f 0 } { 0.15 0.15 0.15 1.0 } }
243             { T{ color-attachment f 1 } { 0.0 0.0 0.0 0.0 } }
244             { depth-attachment 1.0 }
245         } clear-framebuffer
246     ] [
247         {
248             { "primitive-mode"     [ drop triangles-mode ] }
249             { "output-attachments" [ drop { T{ color-attachment f 0 } T{ color-attachment f 1 } } ] }
250             { "uniforms"           [ <bunny-uniforms> ] }
251             { "vertex-array"       [ bunny>> vertex-array>> ] }
252             { "indexes"            [ bunny>> index-elements>> ] }
253             { "framebuffer"        [ sobel>> framebuffer>> ] }
254         } <render-set> render
255     ] bi ;
256
257 : <sobel-uniforms> ( sobel -- uniforms )
258     { 1.0 1.0 } swap
259     [ color-texture>> ] [ normal-texture>> ] [ depth-texture>> ] tri
260     { 0.1 0.0 0.1 1.0 } ! line_color
261     sobel-uniforms boa ;
262
263 : draw-sobel ( world -- )
264     T{ depth-state { comparison f } } set-gpu-state
265
266     sobel>> {
267         { "primitive-mode" [ drop triangle-strip-mode ] }
268         { "indexes"        [ drop T{ index-range f 0 4 } ] }
269         { "uniforms"       [ <sobel-uniforms> ] }
270         { "vertex-array"   [ vertex-array>> ] }
271     } <render-set> render ;
272
273 : draw-sobeled-bunny ( world -- )
274     [ draw-bunny ] [ draw-sobel ] bi ;
275
276 : draw-loading ( world -- )
277     T{ depth-state { comparison f } } set-gpu-state
278
279     loading>> {
280         { "primitive-mode" [ drop triangle-strip-mode ] }
281         { "indexes"        [ drop T{ index-range f 0 4 } ] }
282         { "uniforms"       [ { 1.0 -1.0 } swap texture>> loading-uniforms boa ] }
283         { "vertex-array"   [ vertex-array>> ] }
284     } <render-set> render ;
285
286 M: bunny-world draw-world*
287     dup bunny>>
288     dup bunny-loaded? [
289         dup bunny-state-filled? [ drop ] [ fill-bunny-state ] if
290         draw-sobeled-bunny
291     ] [ drop draw-loading ] if ;
292
293 AFTER: bunny-world resize-world
294     [ sobel>> framebuffer>> ] [ dim>> ] bi resize-framebuffer ;
295
296 M: bunny-world pref-dim* drop { 1024 768 } ;
297 M: bunny-world tick-length drop 1000000 30 /i ;
298 M: bunny-world wasd-movement-speed drop 1/160. ;
299 M: bunny-world wasd-near-plane drop 1/32. ;
300 M: bunny-world wasd-far-plane drop 256.0 ;
301
302 : bunny-window ( -- )
303     [
304         f T{ world-attributes
305             { world-class bunny-world }
306             { title "Bunny" }
307             { pixel-format-attributes {
308                 windowed
309                 double-buffered
310                 T{ depth-bits { value 24 } }
311             } }
312             { grab-input? t }
313         } open-window
314     ] with-ui ;
315
316 MAIN: bunny-window