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