]> gitweb.factorcode.org Git - factor.git/blob - extra/bunny/outlined/outlined.factor
core/basis/extra: use flags{ } in places.
[factor.git] / extra / bunny / outlined / outlined.factor
1 USING: arrays bunny.model bunny.cel-shaded continuations
2 destructors kernel literals math multiline opengl opengl.shaders
3 opengl.framebuffers opengl.gl opengl.textures opengl.demo-support fry
4 opengl.capabilities sequences ui.gadgets combinators accessors
5 macros locals ;
6 FROM: opengl.demo-support => rect-vertices ;
7 IN: bunny.outlined
8
9 STRING: outlined-pass1-fragment-shader-main-source
10 varying vec3 normal;
11 vec4 cel_light();
12
13 void
14 main()
15 {
16     gl_FragData[0] = cel_light();
17     gl_FragData[1] = vec4(normal, 1);
18 }
19
20 ;
21
22 STRING: outlined-pass2-vertex-shader-source
23 varying vec2 coord;
24
25 void
26 main()
27 {
28     gl_Position = ftransform();
29     coord = (gl_Vertex * vec4(0.5) + vec4(0.5)).xy;
30 }
31
32 ;
33
34 STRING: outlined-pass2-fragment-shader-source
35 uniform sampler2D colormap, normalmap, depthmap;
36 uniform vec4 line_color;
37 varying vec2 coord;
38
39 const float DEPTH_RATIO_THRESHOLD = 1.001, SAMPLE_SPREAD = 1.0/512.0;
40
41 float
42 depth_sample(vec2 c)
43 {
44     return texture2D(depthmap, c).x;
45 }
46 bool
47 are_depths_border(vec3 depths)
48 {
49     return any(lessThan(depths, vec3(1.0/DEPTH_RATIO_THRESHOLD)))
50         || any(greaterThan(depths, vec3(DEPTH_RATIO_THRESHOLD)));
51 }
52
53 vec3
54 normal_sample(vec2 c)
55 {
56     return texture2D(normalmap, c).xyz;
57 }
58
59 float
60 min6(float a, float b, float c, float d, float e, float f)
61 {
62     return min(min(min(min(min(a, b), c), d), e), f);
63 }
64
65 float
66 border_factor(vec2 c)
67 {
68     vec2 coord1 = c + vec2(-SAMPLE_SPREAD, -SAMPLE_SPREAD),
69          coord2 = c + vec2( SAMPLE_SPREAD, -SAMPLE_SPREAD),
70          coord3 = c + vec2(-SAMPLE_SPREAD,  SAMPLE_SPREAD),
71          coord4 = c + vec2( SAMPLE_SPREAD,  SAMPLE_SPREAD);
72
73     vec3 normal1 = normal_sample(coord1),
74          normal2 = normal_sample(coord2),
75          normal3 = normal_sample(coord3),
76          normal4 = normal_sample(coord4);
77
78     if (dot(normal1, normal1) < 0.5
79         && dot(normal2, normal2) < 0.5
80         && dot(normal3, normal3) < 0.5
81         && dot(normal4, normal4) < 0.5) {
82         return 0.0;
83     } else {
84         vec4 depths = vec4(depth_sample(coord1),
85                            depth_sample(coord2),
86                            depth_sample(coord3),
87                            depth_sample(coord4));
88
89         vec3 ratios1 = depths.xxx/depths.yzw, ratios2 = depths.yyz/depths.zww;
90
91         if (are_depths_border(ratios1) || are_depths_border(ratios2)) {
92             return 1.0;
93         } else {
94             float normal_border = 1.0 - min6(
95                 dot(normal1, normal2),
96                 dot(normal1, normal3),
97                 dot(normal1, normal4),
98                 dot(normal2, normal3),
99                 dot(normal2, normal4),
100                 dot(normal3, normal4)
101             );
102
103             return normal_border;
104         }
105     }
106 }
107
108 void
109 main()
110 {
111     gl_FragColor = mix(texture2D(colormap, coord), line_color, border_factor(coord));
112 }
113
114 ;
115
116 TUPLE: bunny-outlined
117     gadget
118     pass1-program pass2-program
119     color-texture normal-texture depth-texture
120     framebuffer framebuffer-dim ;
121
122 : outlining-supported? ( -- ? )
123     "3.0" {
124         "GL_ARB_shader_objects"
125         "GL_ARB_draw_buffers"
126         "GL_ARB_multitexture"
127         "GL_EXT_framebuffer_object"
128         "GL_ARB_texture_float"
129     } has-gl-version-or-extensions? ;
130
131 : pass1-program ( -- program )
132     vertex-shader-source <vertex-shader> check-gl-shader
133     cel-shaded-fragment-shader-lib-source <fragment-shader> check-gl-shader
134     outlined-pass1-fragment-shader-main-source <fragment-shader> check-gl-shader
135     3array <gl-program> check-gl-program ;
136
137 : pass2-program ( -- program )
138     outlined-pass2-vertex-shader-source
139     outlined-pass2-fragment-shader-source <simple-gl-program> ;
140
141 : <bunny-outlined> ( gadget -- draw )
142     outlining-supported? [
143         pass1-program pass2-program f f f f f bunny-outlined boa
144     ] [ drop f ] if ;
145
146 :: (framebuffer-texture) ( dim iformat xformat -- texture )
147     GL_TEXTURE0 glActiveTexture
148     gen-texture GL_TEXTURE_2D over glBindTexture
149     GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_CLAMP glTexParameteri
150     GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_CLAMP glTexParameteri
151     GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_NEAREST glTexParameteri
152     GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_NEAREST glTexParameteri
153     GL_TEXTURE_2D 0 iformat dim first2 0 xformat GL_UNSIGNED_BYTE f glTexImage2D ;
154
155 :: (attach-framebuffer-texture) ( texture attachment -- )
156     GL_DRAW_FRAMEBUFFER attachment GL_TEXTURE_2D texture 0 glFramebufferTexture2D
157     gl-error ;
158
159 : (make-framebuffer) ( color-texture normal-texture depth-texture -- framebuffer )
160     3array gen-framebuffer dup [
161         swap GL_COLOR_ATTACHMENT0
162              GL_COLOR_ATTACHMENT1
163              GL_DEPTH_ATTACHMENT 3array [ (attach-framebuffer-texture) ] 2each
164         check-framebuffer
165     ] with-framebuffer ;
166
167 : dispose-framebuffer ( draw -- )
168     dup framebuffer-dim>> [
169         {
170             [ framebuffer>>    [ delete-framebuffer ] when* ]
171             [ color-texture>>  [ delete-texture ] when* ]
172             [ normal-texture>> [ delete-texture ] when* ]
173             [ depth-texture>>  [ delete-texture ] when* ]
174             [ f >>framebuffer-dim drop ]
175         } cleave
176     ] [ drop ] if ;
177
178 MACRO: (framebuffer-texture>>draw) ( iformat xformat setter -- quot )
179     '[ _ _ (framebuffer-texture) [ @ drop ] keep ] ;
180
181 : (make-framebuffer-textures) ( draw dim -- draw color normal depth )
182     {
183         [ drop ]
184         [ GL_RGBA16F GL_RGBA [ >>color-texture  ] (framebuffer-texture>>draw) ]
185         [ GL_RGBA16F GL_RGBA [ >>normal-texture ] (framebuffer-texture>>draw) ]
186         [
187             GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT
188             [ >>depth-texture ] (framebuffer-texture>>draw)
189         ]
190     } 2cleave ;
191
192 : remake-framebuffer ( draw -- )
193     [ dispose-framebuffer ]
194     [ dup gadget>> dim>>
195         [ (make-framebuffer-textures) (make-framebuffer) >>framebuffer ]
196         [ >>framebuffer-dim drop ] bi
197     ] bi ;
198
199 : remake-framebuffer-if-needed ( draw -- )
200     dup [ gadget>> dim>> ] [ framebuffer-dim>> ] bi =
201     [ drop ] [ remake-framebuffer ] if ;
202
203 : clear-framebuffer ( -- )
204     GL_COLOR_ATTACHMENT0 glDrawBuffer
205     0.15 0.15 0.15 1.0 glClearColor
206     flags{ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT } glClear
207     GL_COLOR_ATTACHMENT1 glDrawBuffer
208     0.0 0.0 0.0 0.0 glClearColor
209     GL_COLOR_BUFFER_BIT glClear ;
210
211 : (pass1) ( geom draw -- )
212     dup framebuffer>> [
213         clear-framebuffer
214         { GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT1 } set-draw-buffers
215         pass1-program>> (draw-cel-shaded-bunny)
216     ] with-framebuffer ;
217
218 : (pass2) ( draw -- )
219     GL_PROJECTION glMatrixMode
220     glPushMatrix glLoadIdentity
221     GL_MODELVIEW glMatrixMode
222     glLoadIdentity
223     {
224         [ color-texture>>  GL_TEXTURE_2D GL_TEXTURE0 bind-texture-unit ]
225         [ normal-texture>> GL_TEXTURE_2D GL_TEXTURE1 bind-texture-unit ]
226         [ depth-texture>>  GL_TEXTURE_2D GL_TEXTURE2 bind-texture-unit ]
227         [
228             pass2-program>> [
229                 {
230                     [ "colormap"   glGetUniformLocation 0 glUniform1i ]
231                     [ "normalmap"  glGetUniformLocation 1 glUniform1i ]
232                     [ "depthmap"   glGetUniformLocation 2 glUniform1i ]
233                     [ "line_color" glGetUniformLocation 0.1 0.0 0.1 1.0 glUniform4f ]
234                 } cleave { -1.0 -1.0 } { 1.0 1.0 } rect-vertices
235             ] with-gl-program
236         ]
237     } cleave
238     GL_PROJECTION glMatrixMode
239     glPopMatrix ;
240
241 M: bunny-outlined draw-bunny
242     [ remake-framebuffer-if-needed ]
243     [ (pass1) ]
244     [ (pass2) ] tri ;
245
246 M: bunny-outlined dispose
247     [ pass1-program>> [ delete-gl-program ] when* ]
248     [ pass2-program>> [ delete-gl-program ] when* ]
249     [ dispose-framebuffer ] tri ;