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