+ fb_texture *mask = new fb_texture(w, h, color_model);
+ mask->set_output_texture();
+ glClearColor(cc, cc, cc, cc);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ mask->unset_output_texture();
+
+ unsigned int feather_shader =
+ VFrame::make_shader(0, in_vertex_frag, feather_frag, 0);
+ unsigned int max_shader =
+ VFrame::make_shader(0, in_vertex_frag, max_frag, 0);
+ if( feather_shader && max_shader ) {
+ fb_texture *in = new fb_texture(w, h, color_model);
+ fb_texture *out = new fb_texture(w, h, color_model);
+ float tw = 1./out->get_texture_w(), th = 1./out->get_texture_h();
+ float tw1 = (w-1)*tw, th1 = (h-1)*th;
+ for(int k = 0; k < total_submasks; k++) {
+ MaskEdge &edge = *edges[k];
+ if( edge.size() < 3 ) continue;
+ float r = feathers[k], v = faders[k];
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glActiveTexture(GL_TEXTURE0);
+ glDisable(GL_TEXTURE_2D);
+ float b = r>=0 ? 0. : 1.;
+ float f = r>=0 ? 1. : 0.;
+ glClearColor(b, b, b, b);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColor4f(f, f, f, f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ int display_list = glGenLists(1);
+#if 0
+ glNewList(display_list, GL_COMPILE);
+ glBegin(GL_POLYGON);
+ MaskCoord *c = &edge[0];
+ for( int i=edge.size(); --i>=0; ++c )
+ glVertex2f(c->x, c->y);
+ glEnd();
+ glEndList();
+ glCallList(display_list);
+#else
+ { zglTessData invented;
+ GLUtesselator *tess = gluNewTess();
+ gluTessProperty(tess, GLU_TESS_TOLERANCE, 0.5);
+ gluTessCallback(tess, GLU_TESS_VERTEX,(GLvoid (*)()) &zglVertex);
+ gluTessCallback(tess, GLU_TESS_BEGIN,(GLvoid (*)()) &zglBegin);
+ gluTessCallback(tess, GLU_TESS_END,(GLvoid (*)()) &zglEnd);
+ gluTessCallback(tess, GLU_TESS_COMBINE_DATA,(GLvoid (*)()) &combineData);
+ glNewList(display_list, GL_COMPILE);
+ gluTessBeginPolygon(tess, &invented);
+ gluTessBeginContour(tess);
+ MaskCoord *c = &edge[0];
+ for( int i=edge.size(); --i>=0; ++c )
+ gluTessVertex(tess, (GLdouble *)c, c);
+ gluTessEndContour(tess);
+ gluTessEndPolygon(tess);
+ glEndList();
+ glCallList(display_list);
+ gluDeleteTess(tess); }
+#endif
+ glDeleteLists(1, display_list);
+ in->read_screen(0,0, w,h);
+//in->write_tex("/tmp/in0.ppm");
+ if( r ) {
+ double sig2 = -log(255.0)/(r*r);
+ int n = abs((int)r) + 1;
+ if( n > MAX_FEATHER+1 ) n = MAX_FEATHER+1;
+ float psf[n]; // point spot fn
+ for( int i=0; i<n; ++i )
+ psf[i] = exp(i*i * sig2);
+ glUseProgram(feather_shader);
+ glUniform1fv(glGetUniformLocation(feather_shader, "psf"), n, psf);
+ glUniform1i(glGetUniformLocation(feather_shader, "n"), n);
+ glUniform2f(glGetUniformLocation(feather_shader, "dxy"), tw, 0.);
+ glUniform2f(glGetUniformLocation(feather_shader, "twh"), tw1, th1);
+ glUniform1i(glGetUniformLocation(feather_shader, "tex"), 0);
+ in->bind(0);
+ out->set_output_texture();
+ out->draw_texture(0,0, w,h, 0,0, w,h);
+ out->unset_output_texture();
+//out->write_tex("/tmp/out1.ppm");
+ fb_texture *t = in; in = out; out = t;
+ glUniform2f(glGetUniformLocation(feather_shader, "dxy"), 0., th);
+ in->bind(0);
+ out->set_output_texture();
+ out->draw_texture(0,0, w,h, 0,0, w,h);
+ out->unset_output_texture();
+//out->write_tex("/tmp/out2.ppm");
+ glUseProgram(0);
+ t = in; in = out; out = t;
+ }