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