Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / tracer / tracer.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2015 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include<stdio.h>
22 #include<stdint.h>
23 #include<math.h>
24 #include<string.h>
25 #include<float.h>
26
27 #include "arraylist.h"
28 #include "bccmodels.h"
29 #include "bccolors.h"
30 #include "clip.h"
31 #include "edl.h"
32 #include "edlsession.h"
33 #include "filexml.h"
34 #include "keyframe.h"
35 #include "keyframes.h"
36 #include "tracer.h"
37 #include "transportque.inc"
38 #include "tracerwindow.h"
39 #include "language.h"
40 #include "vframe.h"
41
42 REGISTER_PLUGIN(Tracer)
43
44 void tracer_pgm(const char *fn,VFrame *vfrm)
45 {
46         FILE *fp = fopen(fn,"w");
47         int w = vfrm->get_w(), h = vfrm->get_h();
48         fprintf(fp,"P5\n%d %d\n255\n",w,h);
49         fwrite(vfrm->get_data(),w,h,fp);
50         fclose(fp);
51 }
52
53 TracerPoint::TracerPoint(float x, float y)
54 {
55         this->x = x;      this->y = y;
56 }
57 TracerPoint::~TracerPoint()
58 {
59 }
60
61 int Tracer::new_point()
62 {
63         EDLSession *session = get_edl()->session;
64         float x = !session ? 0.f : session->output_w / 2.f;
65         float y = !session ? 0.f : session->output_h / 2.f;
66         return config.add_point(x, y);
67 }
68
69 TracerConfig::TracerConfig()
70 {
71         draw = 1;  fill = 0;
72         feather = 0;  radius = 1;
73         invert = 0;
74 }
75 TracerConfig::~TracerConfig()
76 {
77 }
78
79 int TracerConfig::equivalent(TracerConfig &that)
80 {
81         if( this->draw != that.draw ) return 0;
82         if( this->fill != that.fill ) return 0;
83         if( this->feather != that.feather ) return 0;
84         if( this->invert != that.invert ) return 0;
85         if( this->radius != that.radius ) return 0;
86         if( this->points.size() != that.points.size() ) return 0;
87         for( int i=0, n=points.size(); i<n; ++i ) {
88                 TracerPoint *ap = this->points[i], *bp = that.points[i];
89                 if( !EQUIV(ap->x, bp->x) ) return 0;
90                 if( !EQUIV(ap->y, bp->y) ) return 0;
91         }
92         return 1;
93 }
94
95 void TracerConfig::copy_from(TracerConfig &that)
96 {
97         this->draw = that.draw;
98         this->fill = that.fill;
99         this->feather = that.feather;
100         this->invert = that.invert;
101         this->radius = that.radius;
102         points.remove_all_objects();
103         for( int i=0,n=that.points.size(); i<n; ++i ) {
104                 TracerPoint *pt = that.points[i];
105                 add_point(pt->x, pt->y);
106         }
107 }
108
109 void TracerConfig::interpolate(TracerConfig &prev, TracerConfig &next,
110                 long prev_frame, long next_frame, long current_frame)
111 {
112         copy_from(prev);
113 }
114
115 void TracerConfig::limits()
116 {
117 }
118
119 int TracerConfig::add_point(float x, float y)
120 {
121         int i = points.size();
122         points.append(new TracerPoint(x, y));
123         return i;
124 }
125
126 void TracerConfig::del_point(int i)
127 {
128         points.remove_object_number(i);
129 }
130
131
132 Tracer::Tracer(PluginServer *server)
133  : PluginVClient(server)
134 {
135         frm = 0; frm_rows = 0;
136         msk = 0; msk_rows = 0;
137         edg = 0; edg_rows = 0;
138         w = 0;   w1 = w-1;
139         h = 0;   h1 = h-1;
140         color_model = bpp = 0;
141         is_float = is_yuv = 0;
142         comps = comp = 0;
143         ax = 0;  ay = 0;
144         bx = 0;  by = 0;
145         cx = 0;  cy = 0;
146         ex = 0;  ey = 0;
147         drag = 0; selected = 0;
148 }
149
150 Tracer::~Tracer()
151 {
152         delete edg;
153         delete msk;
154 }
155
156 const char* Tracer::plugin_title() { return N_("Tracer"); }
157 int Tracer::is_realtime() { return 1; }
158
159 NEW_WINDOW_MACRO(Tracer, TracerWindow);
160 int Tracer::load_configuration1()
161 {
162         KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
163         if( prev_keyframe->position == get_source_position() ) {
164                 read_data(prev_keyframe);
165                 return 1;
166         }
167         return load_configuration();
168 }
169 LOAD_CONFIGURATION_MACRO(Tracer, TracerConfig);
170
171 void Tracer::render_gui(void *data)
172 {
173         Tracer *tracer = (Tracer *)data;
174         tracer->drag = drag;
175 }
176
177 int Tracer::is_dragging()
178 {
179         drag = 0;
180         send_render_gui(this);
181         return drag;
182 }
183
184 void TracerConfig::save_data(KeyFrame *keyframe)
185 {
186         FileXML output;
187
188 // cause data to be stored directly in text
189         output.set_shared_output(keyframe->xbuf);
190
191         output.tag.set_title("TRACER");
192         output.tag.set_property("DRAW", draw);
193         output.tag.set_property("FILL", fill);
194         output.tag.set_property("FEATHER", feather);
195         output.tag.set_property("RADIUS", radius);
196         output.tag.set_property("INVERT", invert);
197         output.append_tag();
198         output.append_newline();
199         output.tag.set_title("/TRACER");
200         output.append_tag();
201         output.append_newline();
202         for( int i=0, n=points.size(); i<n; ++i ) {
203                 TracerPoint *pt = points[i];
204                 char point[BCSTRLEN];
205                 sprintf(point,"/POINT_%d",i+1);
206                 output.tag.set_title(point+1);
207                 output.tag.set_property("X", pt->x);
208                 output.tag.set_property("Y", pt->y);
209                 output.append_tag();
210                 output.tag.set_title(point+0);
211                 output.append_tag();
212                 output.append_newline();
213         }
214         output.terminate_string();
215 }
216 void Tracer::save_data(KeyFrame *keyframe)
217 {
218         config.save_data(keyframe);
219 }
220
221 void TracerConfig::read_data(KeyFrame *keyframe)
222 {
223         FileXML input;
224         input.set_shared_input(keyframe->xbuf);
225         points.remove_all_objects();
226         int result = 0;
227
228         while( !(result=input.read_tag()) ) {
229                 if( input.tag.title_is("TRACER") ) {
230                         draw = input.tag.get_property("DRAW", draw);
231                         fill = input.tag.get_property("FILL", fill);
232                         feather = input.tag.get_property("FEATHER", feather);
233                         radius = input.tag.get_property("RADIUS", radius);
234                         invert = input.tag.get_property("INVERT", invert);
235                         limits();
236                 }
237                 else if( !strncmp(input.tag.get_title(),"POINT_",6) ) {
238                         float x = input.tag.get_property("X", 0.f);
239                         float y = input.tag.get_property("Y", 0.f);
240                         add_point(x, y);
241                 }
242         }
243 }
244 void Tracer::read_data(KeyFrame *keyframe)
245 {
246         config.read_data(keyframe);
247 }
248
249 void Tracer::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
250 {
251         TracerConfig src_config;
252         src_config.read_data(src);
253         KeyFrames *keyframes = (KeyFrames *)src->autos;
254         KeyFrame *prev = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
255         TracerConfig prev_config;
256         prev_config.read_data(prev);
257 // Always update the first one
258         update_parameter(prev_config, src_config, prev);
259         KeyFrame *curr = (KeyFrame*)prev->next;
260         while( curr && curr->position < end ) {
261                 update_parameter(prev_config, src_config, curr);
262                 curr = (KeyFrame*)curr->next;
263         }
264 }
265
266 void TracerPoint::update_parameter(TracerPoint *prev, TracerPoint *src)
267 {
268         if( prev->x != src->x ) x = src->x;
269         if( prev->y != src->y ) y = src->y;
270 }
271
272 void Tracer::update_parameter(TracerConfig &prev_config, TracerConfig &src_config,
273                 KeyFrame *keyframe)
274 {
275         TracerConfig dst_config;
276         dst_config.read_data(keyframe);
277         if( prev_config.draw != src_config.draw )
278                 dst_config.draw = src_config.draw;
279         if( prev_config.fill != src_config.fill )
280                 dst_config.fill = src_config.fill;
281         if( prev_config.feather != src_config.feather )
282                 dst_config.feather = src_config.feather;
283         if( prev_config.invert != src_config.invert )
284                 dst_config.invert = src_config.invert;
285         if( prev_config.radius != src_config.radius )
286                 dst_config.radius = src_config.radius;
287         int src_points = src_config.points.size();
288         int dst_points = dst_config.points.size();
289         int prev_points = prev_config.points.size();
290         int npoints = bmin(prev_points, bmin(src_points, dst_points));
291         for( int i=0; i<npoints; ++i ) {
292                 TracerPoint *prev_point = prev_config.points[i];
293                 TracerPoint *src_point = src_config.points[i];
294                 TracerPoint *dst_point = dst_config.points[i];
295                 dst_point->update_parameter(prev_point, src_point);
296         }
297         dst_config.save_data(keyframe);
298 }
299
300 void Tracer::update_gui()
301 {
302         if( !thread ) return;
303         thread->window->lock_window("Tracer::update_gui");
304         TracerWindow *window = (TracerWindow*)thread->window;
305         if( load_configuration1() ) {
306                 window->update_gui();
307                 window->flush();
308         }
309         thread->window->unlock_window();
310 }
311
312 void Tracer::draw_point(TracerPoint *pt)
313 {
314         int d = bmax(w,h) / 200 + 2;
315         int r = d/2+1, x = pt->x, y = pt->y;
316         frm->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r);
317         frm->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0);
318         frm->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r);
319         frm->draw_smooth(x+0,y+r, x-r, y+r, x-r,y+0);
320 }
321
322 void Tracer::draw_points()
323 {
324         for( int i=0, n=config.points.size(); i<n; ++i ) {
325                 TracerPoint *pt = config.points[i];
326                 frm->set_pixel_color(selected == i ? GREEN : WHITE);
327                 draw_point(pt);
328         }
329 }
330 void Tracer::draw_edge()
331 {
332         float scale = 1 / 255.0f;
333         int color_model = frm->get_color_model();
334         int bpp = BC_CModels::calculate_pixelsize(color_model);
335         switch( color_model ) {
336         case BC_RGB_FLOAT:
337                 for( int y=0; y<h; ++y ) {
338                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
339                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
340                                 if( !*ep ) continue;
341                                 float a = *ep * scale;
342                                 float *px = (float *)sp;
343                                 px[0] = px[1] = px[2] = a;
344                         }
345                 }
346                 break;
347         case BC_RGBA_FLOAT:
348                 for( int y=0; y<h; ++y ) {
349                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
350                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
351                                 if( !*ep ) continue;
352                                 float a = *ep * scale;
353                                 float *px = (float *)sp;
354                                 px[0] = px[1] = px[2] = a;
355                                 px[3] = 1.0f;
356                         }
357                 }
358                 break;
359         case BC_RGB888:
360                 for( int y=0; y<h; ++y ) {
361                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
362                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
363                                 if( !*ep ) continue;
364                                 float a = *ep * scale;
365                                 uint8_t *px = sp;
366                                 px[0] = px[1] = px[2] = a * 255;
367                         }
368                 }
369                 break;
370         case BC_RGBA8888:
371                 for( int y=0; y<h; ++y ) {
372                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
373                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
374                                 if( !*ep ) continue;
375                                 float a = *ep * scale;
376                                 uint8_t *px = sp;
377                                 px[0] = px[1] = px[2] = a * 255;
378                                 px[3] = 0xff;
379                         }
380                 }
381                 break;
382         case BC_YUV888:
383                 for( int y=0; y<h; ++y ) {
384                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
385                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
386                                 if( !*ep ) continue;
387                                 float a = *ep * scale;
388                                 uint8_t *px = sp;
389                                 px[0] = a * 255;
390                                 px[1] = px[2] = 0x80;
391                         }
392                 }
393                 break;
394         case BC_YUVA8888:
395                 for( int y=0; y<h; ++y ) {
396                         uint8_t *sp = frm_rows[y], *ep = edg_rows[y];
397                         for( int x=0; x<w; ++x,++ep,sp+=bpp ) {
398                                 if( !*ep ) continue;
399                                 float a = *ep * scale;
400                                 uint8_t *px = sp;
401                                 px[0] = a * 255;
402                                 px[1] = px[2] = 0x80;
403                                 px[3] = 0xff;
404                         }
405                 }
406                 break;
407         }
408 }
409
410
411 #define PIX_GRADIENT(type, ix, iy) do { \
412         int xi = vx+ix, yi = vy+iy; \
413         if( edg_rows[yi][xi] ) break; \
414         type *px = (type *)(frm_rows[yi] + xi*bpp); \
415         float dv = px[0]-xp[0], v = dv*dv; \
416         for( int c=1; c<comp; ++c ) { \
417                 dv = px[c]-xp[c]; v += dv*dv; \
418         } \
419         v = sqrt(v); \
420         if( vmax < v ) vmax = v; \
421 } while(0)
422 #define ROW_GRADIENT(type, iy) do { \
423         if( vx > 0 ) PIX_GRADIENT(type,-1, iy); \
424         if( iy != 0) PIX_GRADIENT(type, 0, iy); \
425         if( vx < w1) PIX_GRADIENT(type, 1, iy); \
426 } while(0)
427 #define MAX_GRADIENT(type) do { \
428         type *xp = (type *)(frm_rows[vy] + vx*bpp); \
429         if( vy > 0 ) ROW_GRADIENT(type,-1); \
430         ROW_GRADIENT(type, 0); \
431         if( vy < h1 ) ROW_GRADIENT(type, 1); \
432 } while(0)
433
434 #define MAX_PIXEL(type, ix, iy) do { \
435         int vx = cx + ix, vy = cy + iy; \
436         if( edg_rows[vy][vx] ) break; \
437         float vv = FLT_MAX; \
438         int dx = ex-vx, dy = ey-vy; \
439         int rr = dx*dx + dy*dy; \
440         if( rr > dd ) break; \
441         if( rr > 0 ) { \
442                 float r = (float)(ix*dx + iy*dy) / rr; \
443                 float vmax = 0; \
444                 MAX_GRADIENT(type); \
445                 vv = r + vmax; \
446         } \
447         if( maxv < vv ) { \
448                 maxv = vv; \
449                 nx = vx;  ny = vy; \
450         } \
451 } while(0)
452 #define ROW_MAX(type, iy) do { \
453         if( cx >  0 ) MAX_PIXEL(type,-1, iy); \
454         if( iy != 0 ) MAX_PIXEL(type, 0, iy); \
455         if( cx < w1 ) MAX_PIXEL(type, 1, iy); \
456 } while(0)
457
458 int Tracer::step()
459 {
460         int ret = 0;
461         if( !edg_rows[cy][cx] ) {
462                 points.add(cx,cy);
463                 edg_rows[cy][cx] = 0xff;
464         }
465         int dx = ex-cx, dy = ey-cy;
466         int dd = dx*dx + dy*dy;
467         if( !dd ) return ret;
468         int nx = cx, ny = cy;
469         double maxv = -FLT_MAX;
470         if( cy > 0 )  ROW_MAX(uint8_t,-1);
471         ROW_MAX(uint8_t, 0);
472         if( cy < h1 ) ROW_MAX(uint8_t, 1);
473         cx = nx;  cy = ny;
474         return maxv > 0 ? 1 : 0;
475 }
476
477 void Tracer::trace(int i0, int i1)
478 {
479         TracerPoint *pt0 = config.points[i0];
480         TracerPoint *pt1 = config.points[i1];
481         cx = pt0->x;  bclamp(cx, 0, w1);
482         cy = pt0->y;  bclamp(cy, 0, h1);
483         ex = pt1->x;  bclamp(ex, 0, w1);
484         ey = pt1->y;  bclamp(ey, 0, h1);
485         while( step() );
486 }
487
488 int Tracer::smooth()
489 {
490         int &n = points.total, m = 0;
491         if( n < 3 ) return m;
492         TracePoint *ap;
493         TracePoint *bp = &points[0];
494         TracePoint *cp = &points[1];
495         for( ; n>=3; --n ) {
496                 ap = &points[n-1];
497                 if( abs(ap->x-cp->x)<2 && abs(ap->y-cp->y)<2 ) {
498                         edg_rows[bp->y][bp->x] = 0;
499                         ++m;
500                 }
501                 else
502                         break;
503         }
504         if( n < 3 ) return m;
505         ap = &points[0];
506         bp = &points[1];
507         for( int i=2; i<n; ++i ) {
508                 cp = &points[i];
509                 if( abs(ap->x-cp->x)<2 && abs(ap->y-cp->y)<2 &&
510                     ( (bp->x==ap->x || bp->x==cp->x) &&
511                       (bp->y==ap->y || bp->y==cp->y) ) ) {
512                         edg_rows[bp->y][bp->x] = 0;
513                         ++m;
514                 }
515                 else {
516                         ++ap;  ++bp;
517                 }
518                 bp->x = cp->x;  bp->y = cp->y;
519         }
520         n -= m;
521         return m;
522 }
523
524 #if 0
525 int winding2(int x, int y, TracePoints &pts, int n)
526 {
527         int w = 0;
528         int x0 = pts[0].x-x, y0 = pts[0].y-y;
529         for( int x1,y1,i=1; i<n; x0=x1,y0=y1,++i ) { 
530                 x1 = pts[i].x-x;  y1 = pts[i].y-y;
531                 if( y0*y1 < 0 ) {                          // crosses x axis
532                         int xi = x0 - y0*(x1-x0)/(y1-y0);  // x-intercept
533                         if( xi > 0 ) w += y0<0 ? 2 : -2;   // crosses x on plus side
534                 }
535                 else if( !y0 && x0 > 0 ) w += y1>0 ? 1 : -1;
536                 else if( !y1 && x1 > 0 ) w += y0>0 ? 1 : -1;
537         }
538         return w;
539 }
540 #endif
541
542 class FillRegion
543 {
544         class segment { public: int y, lt, rt; };
545         ArrayList<segment> stack;
546
547         void push(int y, int lt, int rt) {
548                 segment &seg = stack.append();
549                 seg.y = y;  seg.lt = lt;  seg.rt = rt;
550         }
551         void pop(int &y, int &lt, int &rt) {
552                 segment &seg = stack.last();
553                 y = seg.y;  lt = seg.lt;  rt = seg.rt;
554                 stack.remove();
555         }
556  
557         int w, h;
558         uint8_t *edg;
559         uint8_t *msk;
560         bool edge_pixel(int i) { return edg[i] > 0; }
561
562 public:
563         void fill(int x, int y);
564         void run();
565
566         FillRegion(VFrame *edg, VFrame *msk);
567 };
568
569 FillRegion::FillRegion(VFrame *edg, VFrame *msk)
570 {
571         this->w = msk->get_w();
572         this->h = msk->get_h();
573         this->msk = (uint8_t*) msk->get_data();
574         this->edg = (uint8_t*) edg->get_data();
575 }
576
577 void FillRegion::fill(int x, int y)
578 {
579         push(y, x, x);
580 }
581
582 void FillRegion::run()
583 {
584         while( stack.size() > 0 ) {
585                 int y, ilt, irt;
586                 pop(y, ilt, irt);
587                 int ofs = y*w + ilt;
588                 for( int x=ilt; x<=irt; ++x,++ofs ) {
589                         if( msk[ofs] ) continue;
590                         msk[ofs] = 0xff;
591                         if( edge_pixel(ofs) ) continue;
592                         int lt = x, rt = x;
593                         int lofs = ofs;
594                         for( int i=lt; --i>=0; lt=i ) {
595                                 if( msk[--lofs] ) break;
596                                 msk[lofs] = 0xff;
597                                 if( edge_pixel(lofs) ) break;
598                         }
599                         int rofs = ofs;
600                         for( int i=rt; ++i< w; rt=i ) {
601                                 if( msk[++rofs] ) break;
602                                 msk[rofs] = 0xff;
603                                 if( edge_pixel(rofs) ) break;
604                         }
605                         if( y+1 <  h ) push(y+1, lt, rt);
606                         if( y-1 >= 0 ) push(y-1, lt, rt);
607                 }
608         }
609 }
610
611 void Tracer::feather(int r, double s)
612 {
613         if( !r ) return;
614         int dir = r < 0 ? (r=-r, -1) : 1;
615         int rr = r * r;
616         int psf[rr];  // pt spot fn
617         float p = powf(10.f, s/2);
618         for( int i=0; i<rr; ++i ) {
619                 float v = powf((float)i/rr,p);
620                 if( dir < 0 ) v = 1-v;
621                 int vv = v*256;
622                 if( vv > 255 ) vv = 255;
623                 psf[i] = vv;
624         }
625         for( int i=0,n=points.size(); i<n; ++i ) {
626                 TracePoint *pt = &points[i];
627                 int xs = pt->x-r, xn=pt->x+r;
628                 bclamp(xs, 0, w);
629                 bclamp(xn, 0, w);
630                 int ys = pt->y-r, yn=pt->y+r;
631                 bclamp(ys, 0, h);
632                 bclamp(yn, 0, h);
633                 for( int y=ys ; y<yn; ++y ) {
634                         for( int x=xs; x<xn; ++x ) {
635                                 int dx = x-pt->x, dy = y-pt->y;
636                                 int dd = dx*dx + dy*dy;
637                                 if( dd >= rr ) continue;
638                                 int v = psf[dd], px = msk_rows[y][x];
639                                 if( dir < 0 ? px<v : px>v ) msk_rows[y][x] = v;
640                         }
641                 }
642         }
643 }
644
645 void Tracer::draw_mask()
646 {
647         switch( color_model ) {
648         case BC_RGB888:
649                 for( int y=0; y<h; ++y ) {
650                         uint8_t *mp = msk_rows[y];
651                         uint8_t *rp = frm_rows[y];
652                         for( int x=0; x<w; rp+=bpp,++x ) {
653                                 int a = !config.invert ? 0xff-mp[x] : mp[x];
654                                 rp[0] = a*rp[0] / 0xff;
655                                 rp[1] = a*rp[1] / 0xff;
656                                 rp[2] = a*rp[2] / 0xff;
657                         }
658                 }
659                 break;
660         case BC_YUV888:
661                 for( int y=0; y<h; ++y ) {
662                         uint8_t *mp = msk_rows[y];
663                         uint8_t *rp = frm_rows[y];
664                         for( int x=0; x<w; rp+=bpp,++x ) {
665                                 int a = !config.invert ? 0xff-mp[x] : mp[x];
666                                 rp[0] = a*rp[0] / 0xff;
667                                 rp[1] = a*(rp[1]-0x80)/0xff + 0x80;
668                                 rp[2] = a*(rp[2]-0x80)/0xff + 0x80;
669                         }
670                 }
671                 break;
672         case BC_RGB_FLOAT:
673                 for( int y=0; y<h; ++y ) {
674                         uint8_t *mp = msk_rows[y];
675                         uint8_t *rp = frm_rows[y];
676                         for( int x=0; x<w; rp+=bpp,++x ) {
677                                 float a = !config.invert ? 1-mp[x]/255.f : mp[x]/255.f;
678                                 float *fp = (float*)rp;
679                                 fp[0] *= a;  fp[1] *= a;  fp[2] *= a;
680                         }
681                 }
682                 break;
683         case BC_RGBA8888:
684         case BC_YUVA8888:
685                 for( int y=0; y<h; ++y ) {
686                         uint8_t *mp = msk_rows[y];
687                         uint8_t *rp = frm_rows[y];
688                         for( int x=0; x<w; rp+=bpp,++x ) {
689                                 rp[3] = !config.invert ? 0xff-mp[x] : mp[x];
690                         }
691                 }
692                 break;
693         case BC_RGBA_FLOAT:
694                 for( int y=0; y<h; ++y ) {
695                         uint8_t *mp = msk_rows[y];
696                         uint8_t *rp = frm_rows[y];
697                         for( int x=0; x<w; rp+=bpp,++x ) {
698                                 float *fp = (float*)rp;
699                                 fp[3] = !config.invert ? 1-mp[x]/255.f : mp[x]/255.f;
700                         }
701                 }
702                 break;
703         }
704 }
705
706 int Tracer::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
707 {
708         int redraw = load_configuration1();
709         frm = frame;
710         frm_rows = frm->get_rows();
711         w = frm->get_w();  w1 = w-1;
712         h = frm->get_h();  h1 = h-1;
713         color_model = frm->get_color_model();
714         bpp = BC_CModels::calculate_pixelsize(color_model);
715         is_float = BC_CModels::is_float(color_model);
716         is_yuv = BC_CModels::is_yuv(color_model);
717         has_alpha = BC_CModels::has_alpha(color_model);
718         comps = BC_CModels::components(color_model);
719         comp = bmin(comps, 3);
720         read_frame(frm, 0, start_position, frame_rate, 0);
721         if( !edg ) redraw = 1;
722         VFrame::get_temp(edg, w, h, BC_GREY8);
723         if( redraw ) {
724                 edg->black_frame();
725                 edg_rows = edg->get_rows();
726
727                 int n = config.points.size()-1;
728                 points.clear();
729                 for( int i=0; i<n; ++i )
730                         trace(i,i+1);
731                 if( n > 0 )
732                         trace(n,0);
733                 while( smooth() > 0 );
734
735                 if( config.fill && points.size() > 2 ) {
736                         int l = points.size(), l2 = l/2;
737                         TracePoint *pt0 = &points[0], *pt1 = &points[l2];
738                         int cx = (pt0->x+pt1->x)/2, cy = (pt0->y+pt1->y)/2;
739                         VFrame::get_temp(msk, w, h, BC_GREY8);
740                         msk->black_frame();
741                         msk_rows = msk->get_rows();
742
743                         FillRegion fill_region(edg, msk);
744                         fill_region.fill(cx, cy);
745                         fill_region.run();
746
747                         feather(config.feather, config.radius);
748                 }
749         }
750         if( config.fill && msk )
751                 draw_mask();
752         if( config.draw && edg )
753                 draw_edge();
754         if( is_dragging() )
755                 draw_points();
756         return 0;
757 }
758