]> gitweb.factorcode.org Git - factor.git/blob - extra/gpu/demos/bunny/bunny.factor
Fixes #2966
[factor.git] / extra / gpu / demos / bunny / bunny.factor
1 ! Copyright (C) 2009 Joe Groff.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types arrays classes.struct combinators
4 combinators.short-circuit game.loop game.worlds gpu gpu.buffers
5 gpu.framebuffers gpu.render gpu.shaders gpu.state gpu.textures
6 gpu.util gpu.util.wasd grouping http.client http.download images
7 images.loader io io.encodings.ascii io.files io.files.temp
8 kernel literals math.parser math.vectors math.vectors.simd
9 method-chains namespaces sequences specialized-arrays
10 specialized-vectors threads ui.gadgets.worlds ui.pixel-formats ;
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 new
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 ] dip while* ; 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
149 "https://downloads.factorcode.org/misc/bun_zipper.ply"
150
151 : download-bunny ( -- path )
152     bunny-model-url bunny-model-path download-once-as ;
153
154 : get-bunny-data ( bunny-state -- )
155     download-bunny bunny-data
156     [ >>vertexes ] [ >>indexes ] bi* drop ;
157
158 : fill-bunny-state ( bunny-state -- )
159     dup [ vertexes>> ] [ indexes>> ] bi <bunny-buffers>
160     [ bunny-program <program-instance> <vertex-array> >>vertex-array ]
161     [ 0 <buffer-ptr> ]
162     [ uint-indexes <index-elements> >>index-elements ] tri*
163     drop ;
164
165 : <bunny-state> ( -- bunny-state )
166     bunny-state new
167     dup [ get-bunny-data ] curry "Downloading bunny model" spawn drop ;
168
169 : bunny-loaded? ( bunny-state -- ? )
170     { [ vertexes>> ] [ indexes>> ] } 1&& ;
171
172 : bunny-state-filled? ( bunny-state -- ? )
173     { [ vertex-array>> ] [ index-elements>> ] } 1&& ;
174
175 : <sobel-state> ( window-vertex-buffer -- sobel-state )
176     sobel-state new
177         swap sobel-program <program-instance> <vertex-array> >>vertex-array
178
179         RGBA half-components T{ texture-parameters
180             { wrap clamp-texcoord-to-edge }
181             { min-filter filter-linear }
182             { min-mipmap-filter f }
183         } <texture-2d> >>color-texture
184         RGBA half-components T{ texture-parameters
185             { wrap clamp-texcoord-to-edge }
186             { min-filter filter-linear }
187             { min-mipmap-filter f }
188         } <texture-2d> >>normal-texture
189         DEPTH u-24-components T{ texture-parameters
190             { wrap clamp-texcoord-to-edge }
191             { min-filter filter-linear }
192             { min-mipmap-filter f }
193         } <texture-2d> >>depth-texture
194
195         dup
196         [
197             [ color-texture>>  0 <texture-2d-attachment> ]
198             [ normal-texture>> 0 <texture-2d-attachment> ] bi 2array
199         ] [ depth-texture>> 0 <texture-2d-attachment> ] bi f { 1024 768 } <framebuffer> >>framebuffer ;
200
201 : <loading-state> ( window-vertex-buffer -- loading-state )
202     loading-state new
203         swap
204         loading-program <program-instance> <vertex-array> >>vertex-array
205
206         RGBA ubyte-components T{ texture-parameters
207             { wrap clamp-texcoord-to-edge }
208             { min-filter filter-linear }
209             { min-mipmap-filter f }
210         } <texture-2d>
211         dup 0 "vocab:gpu/demos/bunny/loading.tiff" load-image allocate-texture-image
212         >>texture ;
213
214 M: bunny-world begin-game-world
215     init-gpu
216
217     { -0.2 0.13 0.1 } 1.1 0.2 set-wasd-view
218
219     <bunny-state> >>bunny
220     <window-vertex-buffer>
221     [ <sobel-state> >>sobel ]
222     [ <loading-state> >>loading ] bi
223     drop ;
224
225 : <bunny-uniforms> ( world -- uniforms )
226     [ wasd-mv-matrix ] [ wasd-p-matrix ] bi
227     { -10000.0 10000.0 10000.0 } ! light position
228     { 0.6 0.5 0.5 1.0 } ! color
229     { 0.2 0.2 0.2 0.2 } ! ambient
230     { 0.8 0.8 0.8 0.8 } ! diffuse
231     100.0 ! shininess
232     bunny-uniforms boa ;
233
234 : draw-bunny ( world -- )
235     T{ depth-state { comparison cmp-less } } set-gpu-state
236
237     [
238         sobel>> framebuffer>> {
239             { T{ color-attachment f 0 } { 0.15 0.15 0.15 1.0 } }
240             { T{ color-attachment f 1 } { 0.0 0.0 0.0 0.0 } }
241             { depth-attachment 1.0 }
242         } clear-framebuffer
243     ] [
244         {
245             { "primitive-mode"     [ drop triangles-mode ] }
246             { "output-attachments" [ drop { T{ color-attachment f 0 } T{ color-attachment f 1 } } ] }
247             { "uniforms"           [ <bunny-uniforms> ] }
248             { "vertex-array"       [ bunny>> vertex-array>> ] }
249             { "indexes"            [ bunny>> index-elements>> ] }
250             { "framebuffer"        [ sobel>> framebuffer>> ] }
251         } <render-set> render
252     ] bi ;
253
254 : <sobel-uniforms> ( sobel -- uniforms )
255     { 1.0 1.0 } swap
256     [ color-texture>> ] [ normal-texture>> ] [ depth-texture>> ] tri
257     { 0.1 0.0 0.1 1.0 } ! line_color
258     sobel-uniforms boa ;
259
260 : draw-sobel ( world -- )
261     T{ depth-state { comparison f } } set-gpu-state
262
263     sobel>> {
264         { "primitive-mode" [ drop triangle-strip-mode ] }
265         { "indexes"        [ drop T{ index-range f 0 4 } ] }
266         { "uniforms"       [ <sobel-uniforms> ] }
267         { "vertex-array"   [ vertex-array>> ] }
268     } <render-set> render ;
269
270 : draw-sobeled-bunny ( world -- )
271     [ draw-bunny ] [ draw-sobel ] bi ;
272
273 : draw-loading ( world -- )
274     T{ depth-state { comparison f } } set-gpu-state
275
276     loading>> {
277         { "primitive-mode" [ drop triangle-strip-mode ] }
278         { "indexes"        [ drop T{ index-range f 0 4 } ] }
279         { "uniforms"       [ { 1.0 -1.0 } swap texture>> loading-uniforms boa ] }
280         { "vertex-array"   [ vertex-array>> ] }
281     } <render-set> render ;
282
283 M: bunny-world draw-world*
284     dup bunny>>
285     dup bunny-loaded? [
286         dup bunny-state-filled? [ drop ] [ fill-bunny-state ] if
287         draw-sobeled-bunny
288     ] [ drop draw-loading ] if ;
289
290 AFTER: bunny-world resize-world
291     [ sobel>> framebuffer>> ] [ dim>> ] bi resize-framebuffer ;
292
293 M: bunny-world wasd-movement-speed drop 1/160. ;
294 M: bunny-world wasd-near-plane drop 1/32. ;
295 M: bunny-world wasd-far-plane drop 256.0 ;
296
297 GAME: bunny-game {
298         { world-class bunny-world }
299         { title "Bunny" }
300         { pixel-format-attributes {
301             windowed
302             double-buffered
303             T{ depth-bits { value 24 } }
304         } }
305         { grab-input? t }
306         { use-game-input? t }
307         { pref-dim { 1024 768 } }
308         { tick-interval-nanos $[ 60 fps ] }
309     } ;