rework keyframe hide popup, keyframe auto render, textbox set_selection wide text
[goodguy/history.git] / cinelerra-5.1 / plugins / bluebanana / bluebananaengine.C
1 /*
2  * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
3  * Copyright (C) 2012-2013 Monty <monty@xiph.org>
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 <math.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "bluebanana.h"
27 #include "bluebananaconfig.h"
28 #include "loadbalance.h"
29 #include "bluebananacolor.c" // need the inlines
30
31 BluebananaPackage::BluebananaPackage(BluebananaEngine *engine) : LoadPackage(){
32   this->engine=engine;
33 }
34
35 BluebananaUnit::BluebananaUnit(BluebananaEngine *server,
36                                BluebananaMain *plugin) : LoadClient(server) {
37   this->plugin = plugin;
38   this->server = server;
39 }
40
41 BluebananaUnit::~BluebananaUnit(){}
42
43 void BluebananaUnit::process_package(LoadPackage *package){
44   BluebananaPackage *pkg = (BluebananaPackage*)package;
45   BluebananaEngine *engine = (BluebananaEngine*)pkg->engine;
46
47   VFrame *frame = engine->data;
48   int w = frame->get_w();
49   int h = frame->get_h();
50   int ant = plugin->ants_counter;
51   int gui_open = plugin->gui_open();
52   int show_ants = plugin->config.mark && gui_open;
53   int j;
54
55   int active = plugin->config.active;
56   int use_mask = plugin->config.use_mask;
57   int capture_mask = plugin->config.capture_mask;
58   int invert_selection = plugin->config.invert_selection;
59
60   float *Hl = (plugin->config.Hsel_active &&
61                (plugin->config.Hsel_lo!=0 ||
62                 plugin->config.Hsel_hi!=360)) ? plugin->hue_select_alpha_lookup : NULL;
63   float *Sl = (plugin->config.Ssel_active &&
64                (plugin->config.Ssel_lo!=0  ||
65                 plugin->config.Ssel_hi!=100)) ? plugin->sat_select_alpha_lookup : NULL;
66   float *Vl = (plugin->config.Vsel_active &&
67                (plugin->config.Vsel_lo!=0 ||
68                 plugin->config.Vsel_hi!=100)) ? plugin->val_select_alpha_lookup : NULL;
69
70   float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
71
72   float *Sal = (plugin->config.Sadj_active &&
73                 (plugin->config.Sadj_lo!=0 ||
74                  plugin->config.Sadj_hi!=100 ||
75                  plugin->config.Sadj_gamma!=1)) ? plugin->sat_adj_lookup : NULL;
76   float *Val = (plugin->config.Vadj_active &&
77                 (plugin->config.Vadj_lo!=0 ||
78                  plugin->config.Vadj_hi!=100 ||
79                  plugin->config.Vadj_gamma!=1)) ? plugin->val_adj_lookup : NULL;
80   float *Ral = (plugin->config.Radj_active &&
81                 (plugin->config.Radj_lo!=0 ||
82                  plugin->config.Radj_hi!=100 ||
83                  plugin->config.Radj_gamma!=1)) ? plugin->red_adj_lookup : NULL;
84   float *Gal = (plugin->config.Gadj_active &&
85                 (plugin->config.Gadj_lo!=0 ||
86                  plugin->config.Gadj_hi!=100 ||
87                  plugin->config.Gadj_gamma!=1)) ? plugin->green_adj_lookup : NULL;
88   float *Bal = (plugin->config.Badj_active &&
89                 (plugin->config.Badj_lo!=0 ||
90                  plugin->config.Badj_hi!=100 ||
91                  plugin->config.Badj_gamma!=1)) ? plugin->blue_adj_lookup : NULL;
92
93   float Sas = plugin->sat_adj_toe_slope;
94   float Vas = plugin->val_adj_toe_slope;
95   float Ras = plugin->red_adj_toe_slope;
96   float Gas = plugin->green_adj_toe_slope;
97   float Bas = plugin->blue_adj_toe_slope;
98
99   float Aal = plugin->config.Oadj_active ? plugin->config.Oadj_val*.01 : 1.f;
100
101   float Vscale = (plugin->config.Vadj_hi-plugin->config.Vadj_lo) / 100.f;
102   float Vshift = plugin->config.Vadj_lo / 100.f;
103   float Vgamma = plugin->config.Vadj_gamma;
104
105   int doRGB = Ral || Gal || Bal;
106
107   int doHSV = (Hal!=0) || Sal || Val;
108
109   int doSEL = ( Hl || Sl || Vl ) && (active || show_ants);
110
111   int shaping = plugin->config.Fsel_active && doSEL &&
112     (plugin->config.Fsel_lo || plugin->config.Fsel_hi || plugin->config.Fsel_over);
113
114   int byte_advance=0;
115   int have_alpha=1;
116
117 #define SPLIT 128
118
119   int tasks = engine->get_total_packages()*16;
120   int taski,rowi,coli;
121
122   /* do as much work entirely local to thread memory as possible */
123   unsigned char row_fragment[SPLIT*16];
124   float *selection_fullframe=NULL;
125   float  selection[SPLIT];
126
127   float Rvec[SPLIT];
128   float Gvec[SPLIT];
129   float Bvec[SPLIT];
130
131   float Avec[SPLIT];
132   float Hvec[SPLIT];
133   float Svec[SPLIT];
134   float Vvec[SPLIT];
135
136   float *Rhist = pkg->Rhist;
137   float *Ghist = pkg->Ghist;
138   float *Bhist = pkg->Bhist;
139   float *Hhist = pkg->Hhist;
140   float *Shist = pkg->Shist;
141   float *Vhist = pkg->Vhist;
142   float Htotal=0.f;
143   float Hweight=0.f;
144
145   float *Hhr = pkg->Hhr;
146   float *Hhg = pkg->Hhg;
147   float *Hhb = pkg->Hhb;
148   float *Shr = pkg->Shr;
149   float *Shg = pkg->Shg;
150   float *Shb = pkg->Shb;
151   float *Vhr = pkg->Vhr;
152   float *Vhg = pkg->Vhg;
153   float *Vhb = pkg->Vhb;
154
155   memset(Rhist,0,sizeof(pkg->Rhist));
156   memset(Ghist,0,sizeof(pkg->Ghist));
157   memset(Bhist,0,sizeof(pkg->Bhist));
158   memset(Hhist,0,sizeof(pkg->Hhist));
159   memset(Shist,0,sizeof(pkg->Shist));
160   memset(Vhist,0,sizeof(pkg->Vhist));
161
162   memset(Hhr,0,sizeof(pkg->Hhr));
163   memset(Hhg,0,sizeof(pkg->Hhg));
164   memset(Hhb,0,sizeof(pkg->Hhb));
165   memset(Shr,0,sizeof(pkg->Shr));
166   memset(Shg,0,sizeof(pkg->Shg));
167   memset(Shb,0,sizeof(pkg->Shb));
168   memset(Vhr,0,sizeof(pkg->Vhr));
169   memset(Vhg,0,sizeof(pkg->Vhg));
170   memset(Vhb,0,sizeof(pkg->Vhb));
171
172   /* If we're doing fill shaping, we need to compute base selection
173      for the entire frame before shaping. */
174
175   if(shaping){
176     engine->set_task(tasks*2,"shaping_even");
177     while ( (taski = engine->next_task()) >= 0){
178
179     /* operate on discontinuous, interleaved sections of the source
180        buffer in two passes.  Although we could take extra steps to
181        make cache contention across cores completely impossible, the
182        extra locking and central join required isn't worth it.  It's
183        preferable to make contention merely highly unlikely. */
184
185       int start_row, end_row;
186       if(taski<tasks){
187         start_row = (taski*2)*h/(tasks*2);
188         end_row = (taski*2+1)*h/(tasks*2);
189       }else{
190         start_row = ((taski-tasks)*2+1)*h/(tasks*2);
191         end_row = ((taski-tasks)*2+2)*h/(tasks*2);
192       }
193
194       for(rowi = start_row; rowi<end_row; rowi++){
195         unsigned char *row = frame->get_rows()[rowi];
196
197         for(coli=0;coli<w;coli+=SPLIT){
198
199           int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
200           float *A = engine->selection_workA+w*rowi+coli;
201
202           switch(frame->get_color_model()) {
203           case BC_RGB888:
204             rgb8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
205             row += todo*3;
206             break;
207           case BC_RGBA8888:
208             rgba8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
209             row += todo*4;
210             break;
211           case BC_RGB_FLOAT:
212             rgbF_to_RGB((float *)row,Rvec,Gvec,Bvec,todo);
213             row += todo*12;
214             break;
215           case BC_RGBA_FLOAT:
216             rgbaF_to_RGBA((float *)row,Rvec,Gvec,Bvec,Avec,todo);
217             row += todo*16;
218             break;
219           case BC_YUV888:
220             yuv8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
221             row += todo*3;
222             break;
223           case BC_YUVA8888:
224             yuva8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
225             row += todo*4;
226             break;
227           }
228
229           for(j = 0; j < todo; j++)
230             RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
231
232           if(Hl)
233             for(j = 0; j < todo; j++)
234               selection[j]=sel_lookup(Hvec[j]*.166666667f,Hl);
235           else
236             for(j = 0; j < todo; j++)
237               selection[j]=1.f;
238
239           if(Sl)
240             for(j = 0; j < todo; j++)
241               selection[j]*=sel_lookup(Svec[j],Sl);
242
243           if(Vl)
244             for(j = 0; j < todo; j++)
245               selection[j]*=sel_lookup(Vvec[j],Vl);
246
247           /* lock the memcpy to prevent pessimal cache coherency
248              interleave across cores. */
249           pthread_mutex_lock(&engine->copylock);
250           memcpy(A,selection,sizeof(*selection)*todo);
251           pthread_mutex_unlock(&engine->copylock);
252         }
253       }
254     }
255
256     /* Perform fill shaping on the selection */
257     selection_fullframe = plugin->fill_selection(engine->selection_workA,
258                                                  engine->selection_workB, w, h, engine);
259   }
260
261   /* row-by-row color modification and histogram feedback */
262   engine->set_task(tasks*2,"modification_even");
263   while((taski = engine->next_task())>=0){
264
265     /* operate on discontinuous, interleaved sections of the source
266        buffer in two passes.  Although we could take extra steps to
267        make cache contention across cores completely impossible, the
268        extra locking and central join required isn't worth it.  It's
269        preferable to make contention merely highly unlikely. */
270
271     int start_row, end_row;
272     if(taski<tasks){
273       start_row = (taski*2)*h/(tasks*2);
274       end_row = (taski*2+1)*h/(tasks*2);
275     }else{
276       start_row = ((taski-tasks)*2+1)*h/(tasks*2);
277       end_row = ((taski-tasks)*2+2)*h/(tasks*2);
278     }
279
280     for(rowi = start_row; rowi<end_row; rowi++){
281       unsigned char *row = frame->get_rows()[rowi];
282
283       for(int coli=0;coli<w;coli+=SPLIT){
284         int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
285         int have_selection = 0;
286
287         /* convert from pipeline color format */
288         if(active || show_ants || (use_mask && capture_mask && have_alpha)){
289
290           switch(frame->get_color_model()) {
291           case BC_RGB888:
292             pthread_mutex_lock(&engine->copylock);
293             memcpy(row_fragment,row,todo*3);
294             pthread_mutex_unlock(&engine->copylock);
295             rgb8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
296             byte_advance = todo*3;
297             have_alpha=0;
298             break;
299
300           case BC_RGBA8888:
301             pthread_mutex_lock(&engine->copylock);
302             memcpy(row_fragment,row,todo*4);
303             pthread_mutex_unlock(&engine->copylock);
304             rgba8_to_RGBA(row_fragment,Rvec,Gvec,Bvec,Avec,todo);
305             byte_advance = todo*4;
306             have_alpha=1;
307             break;
308
309           case BC_RGB_FLOAT:
310             pthread_mutex_lock(&engine->copylock);
311             memcpy(row_fragment,row,todo*12);
312             pthread_mutex_unlock(&engine->copylock);
313             rgbF_to_RGB((float *)row_fragment,Rvec,Gvec,Bvec,todo);
314             byte_advance = todo*12;
315             have_alpha=0;
316             break;
317
318           case BC_RGBA_FLOAT:
319             pthread_mutex_lock(&engine->copylock);
320             memcpy(row_fragment,row,todo*16);
321             pthread_mutex_unlock(&engine->copylock);
322             rgbaF_to_RGBA((float *)row_fragment,Rvec,Gvec,Bvec,Avec,todo);
323             byte_advance = todo*16;
324             have_alpha=1;
325             break;
326
327           case BC_YUV888:
328             pthread_mutex_lock(&engine->copylock);
329             memcpy(row_fragment,row,todo*3);
330             pthread_mutex_unlock(&engine->copylock);
331             yuv8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
332             byte_advance = todo*3;
333             have_alpha=0;
334             break;
335
336           case BC_YUVA8888:
337             pthread_mutex_lock(&engine->copylock);
338             memcpy(row_fragment,row,todo*4);
339             pthread_mutex_unlock(&engine->copylock);
340             yuva8_to_RGBA(row,Rvec,Gvec,Bvec,Avec,todo);
341             byte_advance = todo*4;
342             have_alpha=1;
343             break;
344           }
345
346           if(doSEL)
347             /* generate initial HSV values [if selection active] */
348             for(j = 0; j < todo; j++)
349               RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
350
351
352           float selection_test=todo;
353
354           if(selection_fullframe){
355
356             /* get the full-frame selection data we need into thread-local storage */
357             /* the full-frame data is read-only at this point, no need to lock */
358             float *sf = selection_fullframe + rowi*w + coli;
359             selection_test=0.f;
360             for(j = 0; j < todo; j++)
361               selection_test += selection[j] = sf[j];
362             have_selection=1;
363
364           }else{
365
366             /* selection computation when no full-frame shaping */
367             if(Hl){
368               selection_test=0.f;
369               for(j = 0; j < todo; j++)
370                 selection_test += selection[j] = sel_lookup(Hvec[j]*.166666667f,Hl);
371               have_selection=1;
372             }
373
374             if(Sl){
375               if(have_selection){
376                 if(selection_test>SELECT_THRESH){
377                   selection_test=0.f;
378                   for(j = 0; j < todo; j++)
379                     selection_test += selection[j] *= sel_lookup(Svec[j],Sl);
380                 }
381               }else{
382                 selection_test=0.f;
383                 for(j = 0; j < todo; j++)
384                   selection_test += selection[j] = sel_lookup(Svec[j],Sl);
385                 have_selection=1;
386               }
387             }
388
389             if(Vl){
390               if(have_selection){
391                 if(selection_test>SELECT_THRESH){
392                   selection_test=0.f;
393                   for(j = 0; j < todo; j++)
394                     selection_test += selection[j] *= sel_lookup(Vvec[j],Vl);
395                 }
396               }else{
397                 selection_test=0.f;
398                 for(j = 0; j < todo; j++)
399                   selection_test += selection[j] = sel_lookup(Vvec[j],Vl);
400                 have_selection=1;
401               }
402             }
403           }
404
405           /* selection modification according to config */
406           if(use_mask && have_alpha){
407             if(!have_selection){
408               /* selection consists only of mask */
409               selection_test=0.;
410               for(j = 0; j < todo; j++)
411                 selection_test += selection[j] = Avec[j];
412               have_selection=1;
413             }else{
414               if(invert_selection){
415                 if(selection_test < SELECT_THRESH){
416                   /* fully selected after invert, clip to mask */
417                   selection_test=0.f;
418                   for(j = 0; j < todo; j++)
419                     selection_test += selection[j] = Avec[j];
420                 }else if (selection_test >= todo-SELECT_THRESH){
421                   /* fully deselected after invert */
422                   selection_test=0.;
423                 }else{
424                   /* partial selection after invert, clip to mask */
425                   selection_test=0.f;
426                   for(j = 0; j < todo; j++)
427                     selection_test += selection[j] = Avec[j]*(1.f-selection[j]);
428                 }
429               }else{
430                 if(selection_test < SELECT_THRESH){
431                   /* fully deselected */
432                 }else if (selection_test >= todo-SELECT_THRESH){
433                   /* fully selected, clip to mask */
434                   selection_test=0.f;
435                   for(j = 0; j < todo; j++)
436                     selection_test += selection[j] = Avec[j];
437                 }else{
438                   /* partial selection, clip to mask */
439                   selection_test=0.f;
440                   for(j = 0; j < todo; j++)
441                     selection_test += selection[j] *= Avec[j];
442                 }
443               }
444             }
445             if(selection_test < SELECT_THRESH){
446               /* skip processing this fragment */
447               /* we're using a mask; if the mask is set to capture, we
448                  need to restore alpha before skipping */
449               if(capture_mask){
450                 switch(frame->get_color_model()) {
451                 case BC_RGBA8888:
452                   unmask_rgba8(row_fragment,todo);
453                   break;
454                 case BC_RGBA_FLOAT:
455                   unmask_rgbaF((float *)row_fragment,todo);
456                   break;
457                 case BC_YUVA8888:
458                   unmask_yuva8(row_fragment,todo);
459                   break;
460                 }
461                 pthread_mutex_lock(&engine->copylock);
462                 memcpy(row,row_fragment,byte_advance);
463                 pthread_mutex_unlock(&engine->copylock);
464               }
465
466               row+=byte_advance;
467               continue;
468             }
469             if(selection_test > todo-SELECT_THRESH)
470               have_selection=0; // fully selected
471           }else{
472             if(have_selection){
473               if(invert_selection){
474                 if(selection_test < SELECT_THRESH){
475                   /* fully selected after inversion */
476                   selection_test=todo;
477                 }else if (selection_test >= todo-SELECT_THRESH){
478                   /* fully deselected after invert, skip fragment */
479                   row+=byte_advance;
480                   continue;
481                 }else{
482                   /* partial selection */
483                   selection_test=0.f;
484                   for(j = 0; j < todo; j++)
485                     selection_test += selection[j] = (1.f-selection[j]);
486                 }
487               }else{
488                 if(selection_test < SELECT_THRESH){
489                   /* fully deselected, skip fragment */
490                   row+=byte_advance;
491                   continue;
492                 }else if (selection_test >= todo-SELECT_THRESH){
493                   /* fully selected */
494                   selection_test=todo;
495                 }else{
496                   /* partial selection; already calculated */
497                 }
498               }
499               if(selection_test < SELECT_THRESH){
500                   row+=byte_advance;
501                   continue; // inactive fragment
502               }
503               if(selection_test > todo-SELECT_THRESH)
504                 have_selection=0; // fully selected
505             }else{
506               if(invert_selection){
507                   row+=byte_advance;
508                   continue;
509               }
510             }
511           }
512         }
513
514         if(active){
515
516           /* red adjust */
517           if(Ral) {
518             if(have_selection){
519               for(j = 0; j < todo; j++)
520                 if(selection[j]>SELECT_THRESH) Rvec[j]=adj_lookup(Rvec[j],Ral,Ras);
521             }else{
522               for(j = 0; j < todo; j++)
523                 Rvec[j] = adj_lookup(Rvec[j],Ral,Ras);
524             }
525           }
526           /* red histogram */
527           if(gui_open){
528             if(have_selection){
529               for(j = 0; j < todo; j++)
530                 if(selection[j]>SELECT_THRESH) Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
531             }else{
532               for(j = 0; j < todo; j++)
533                 Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
534             }
535           }
536
537           /* green adjust */
538           if(Gal) {
539             if(have_selection){
540               for(j = 0; j < todo; j++)
541                 if(selection[j]>SELECT_THRESH) Gvec[j]=adj_lookup(Gvec[j],Gal,Gas);
542             }else{
543               for(j = 0; j < todo; j++)
544                 Gvec[j] = adj_lookup(Gvec[j],Gal,Gas);
545             }
546           }
547           /* green histogram */
548           if(gui_open){
549             if(have_selection){
550               for(j = 0; j < todo; j++)
551                 if(selection[j]>SELECT_THRESH) Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
552             }else{
553               for(j = 0; j < todo; j++)
554                 Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
555             }
556           }
557
558           /* blue adjust */
559           if(Bal) {
560             if(have_selection){
561               for(j = 0; j < todo; j++)
562                 if(selection[j]>SELECT_THRESH) Bvec[j]=adj_lookup(Bvec[j],Bal,Bas);
563             }else{
564               for(j = 0; j < todo; j++)
565                 Bvec[j] = adj_lookup(Bvec[j],Bal,Bas);
566             }
567           }
568           /* blue histogram */
569           if(gui_open){
570             if(have_selection){
571               for(j = 0; j < todo; j++)
572                 if(selection[j]>SELECT_THRESH) Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
573             }else{
574               for(j = 0; j < todo; j++)
575                 Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
576             }
577           }
578
579           /* compute HSV values or update values from earlier selection work if
580              they've changed */
581           if( (!doSEL || doRGB) && // not yet computed, or since modified
582               (doHSV || gui_open) ) // needed for HSV mod and/or histograms
583             for(j = 0; j < todo; j++)
584               RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
585
586           if(doHSV){
587             /* H modification */
588             /* don't bother checking selection, H adj is lightweight */
589             if(Hal){
590               for(j = 0; j < todo; j++){
591                 Hvec[j] += Hal;
592                 if(Hvec[j]<0.f)Hvec[j]+=6.f;
593                 if(Hvec[j]>=6.f)Hvec[j]-=6.f;
594               }
595             }
596             /* H histogram */
597             /* this is pre-shift RGB data; shift hue later to save an HSV->RGB transform */
598             if(gui_open){
599               if(have_selection){
600                 for(j = 0; j < todo; j++){
601                   if(selection[j]>SELECT_THRESH){
602                     float weight = selection[j]*Svec[j];
603                     int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
604                     Htotal += selection[j];
605                     Hweight += weight;
606                     Hhist[bin] += weight;
607                     Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
608                     Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
609                     Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
610                   }
611                 }
612               }else{
613                 for(j = 0; j < todo; j++){
614                   float weight = Svec[j];
615                   int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
616                   Htotal += 1.f;
617                   Hweight += weight;
618                   Hhist[bin] += weight;
619                   Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
620                   Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
621                   Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
622                 }
623               }
624             }
625
626             /* S modification */
627             if(Sal) {
628               if(have_selection){
629                 for(j = 0; j < todo; j++)
630                   if(selection[j]>SELECT_THRESH) Svec[j] = adj_lookup(Svec[j],Sal,Sas);
631               }else{
632                 for(j = 0; j < todo; j++)
633                   Svec[j] = adj_lookup(Svec[j],Sal,Sas);
634               }
635             }
636
637             /* This is unrolled a few times below...
638                Although we're using HSV, we don't want hue/saturation
639                changes to have a strong effect on apparent brightness.
640                Apply a correction to V (not Y!) based on luma change. */
641             /* Calculate new RGB values at same time */
642             if(Hal || Sal){
643               if(have_selection){
644                 for(j = 0; j < todo; j++){
645                   if(selection[j]>SELECT_THRESH){
646                     HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
647                     /* run S histogram at the same time as we've got
648                        the RGB data */
649                     if(gui_open){
650                       int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
651                       Shist[bin] += selection[j];
652                       Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
653                       Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
654                       Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
655                     }
656                   }
657                 }
658               }else{
659                 for(j = 0; j < todo; j++){
660                   HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
661                   if(gui_open){
662                     int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
663                     Shist[bin] += 1.f;
664                     Shr[bin>>HRGBSHIFT] += Rvec[j];
665                     Shg[bin>>HRGBSHIFT] += Gvec[j];
666                     Shb[bin>>HRGBSHIFT] += Bvec[j];
667                   }
668                 }
669               }
670             }else{
671               if(gui_open){
672                 if(have_selection){
673                   for(j = 0; j < todo; j++){
674                     if(selection[j]>SELECT_THRESH){
675                       int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
676                       Shist[bin] += selection[j];
677                       Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
678                       Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
679                       Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
680                     }
681                   }
682                 }else{
683                   for(j = 0; j < todo; j++){
684                     int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
685                     Shist[bin] += 1.f;
686                     Shr[bin>>HRGBSHIFT] += Rvec[j];
687                     Shg[bin>>HRGBSHIFT] += Gvec[j];
688                     Shb[bin>>HRGBSHIFT] += Bvec[j];
689                   }
690                 }
691               }
692             }
693
694             /* V modification */
695             /* This one is a bit unlike the others; Value gamma
696                behavior is conditional.  When < 1.0 (darkening the
697                picture) gamma directly operates on Value as normally
698                expected (thus scaling R G and B about zero).  When
699                gamma > 1.0 (lightening the picture) it operates on the
700                Value scale's zero point rather than the Value.  Both
701                are done to get the most natural behavior out of
702                saturation as gamma changes.  The only drawback: One
703                can no longer reverse a gamma operation by applying the
704                inverse gamma in a subsequent step. */
705             if(Val){
706               if(have_selection){
707                 if(Vgamma<1.0){
708                   /* scale mode */
709                   for(j = 0; j < todo; j++)
710                     if(selection[j]>SELECT_THRESH){
711                       float scale = adj_lookup(Vvec[j],Val,Vas);
712                       Vvec[j] = Vvec[j] * scale + Vshift;
713                       Rvec[j] = Rvec[j] * scale + Vshift;
714                       Gvec[j] = Gvec[j] * scale + Vshift;
715                       Bvec[j] = Bvec[j] * scale + Vshift;
716                     }
717                 }else{
718                   /* shift mode */
719                   for(j = 0; j < todo; j++)
720                     if(selection[j]>SELECT_THRESH){
721                       float shift = adj_lookup(Vvec[j],Val,Vas);
722                       Vvec[j] = Vvec[j] * Vscale + shift;
723                       Rvec[j] = Rvec[j] * Vscale + shift;
724                       Gvec[j] = Gvec[j] * Vscale + shift;
725                       Bvec[j] = Bvec[j] * Vscale + shift;
726                     }
727                 }
728               }else{
729                 if(Vgamma<1.0){
730                   /* scale mode */
731                   for(j = 0; j < todo; j++){
732                     float scale = adj_lookup(Vvec[j],Val,Vas);
733                     Vvec[j] = Vvec[j] * scale + Vshift;
734                     Rvec[j] = Rvec[j] * scale + Vshift;
735                     Gvec[j] = Gvec[j] * scale + Vshift;
736                     Bvec[j] = Bvec[j] * scale + Vshift;
737                   }
738                 }else{
739                   /* shift mode */
740                   for(j = 0; j < todo; j++){
741                     float shift = adj_lookup(Vvec[j],Val,Vas);
742                     Vvec[j] = Vvec[j] * Vscale + shift;
743                     Rvec[j] = Rvec[j] * Vscale + shift;
744                     Gvec[j] = Gvec[j] * Vscale + shift;
745                     Bvec[j] = Bvec[j] * Vscale + shift;
746                   }
747                 }
748               }
749             }
750
751             /* V histogram */
752             if(gui_open){
753               if(have_selection){
754                 for(j = 0; j < todo; j++){
755                   if(selection[j]>SELECT_THRESH){
756                     int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
757                     Vhist[bin] += selection[j];
758                     Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
759                     Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
760                     Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
761                   }
762                 }
763               }else{
764                 for(j = 0; j < todo; j++){
765                   int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
766                   Vhist[bin] += 1.f;
767                   Vhr[bin>>HRGBSHIFT] += Rvec[j];
768                   Vhg[bin>>HRGBSHIFT] += Gvec[j];
769                   Vhb[bin>>HRGBSHIFT] += Bvec[j];
770                 }
771               }
772             }
773
774           }else if (gui_open){
775
776             if(have_selection){
777               /* H histogram */
778               for(j = 0; j < todo; j++){
779                 if(selection[j]>SELECT_THRESH){
780                   float weight = selection[j]*Svec[j];
781                   int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
782                   Htotal += selection[j];
783                   Hweight += weight;
784                   Hhist[bin] += weight;
785                   Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
786                   Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
787                   Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
788                 }
789               }
790               /* S histogram */
791               for(j = 0; j < todo; j++){
792                 if(selection[j]>SELECT_THRESH){
793                   int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
794                   Shist[bin] += selection[j];
795                   Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
796                   Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
797                   Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
798                 }
799               }
800               /* V histogram */
801               for(j = 0; j < todo; j++){
802                 if(selection[j]>SELECT_THRESH){
803                   int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
804                   Vhist[bin] += selection[j];
805                   Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
806                   Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
807                   Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
808                 }
809               }
810             }else{
811
812               /* H histogram */
813               for(j = 0; j < todo; j++){
814                 float weight = Svec[j];
815                 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
816                 Htotal += 1.f;
817                 Hweight += weight;
818                 Hhist[bin] += weight;
819                 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
820                 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
821                 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
822               }
823               /* S histogram */
824               for(j = 0; j < todo; j++){
825                 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
826                 Shist[bin] += 1.f;
827                 Shr[bin>>HRGBSHIFT] += Rvec[j];
828                 Shg[bin>>HRGBSHIFT] += Gvec[j];
829                 Shb[bin>>HRGBSHIFT] += Bvec[j];
830               }
831               /* V histogram */
832               for(j = 0; j < todo; j++){
833                 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
834                 Vhist[bin] += 1.f;
835                 Vhr[bin>>HRGBSHIFT] += Rvec[j];
836                 Vhg[bin>>HRGBSHIFT] += Gvec[j];
837                 Vhb[bin>>HRGBSHIFT] += Bvec[j];
838               }
839             }
840           }
841
842           /* layer back into pipeline color format; master fader applies here */
843           switch(frame->get_color_model()) {
844           case BC_RGB888:
845             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
846             break;
847           case BC_RGBA8888:
848             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
849             break;
850           case BC_RGB_FLOAT:
851             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,3);
852             break;
853           case BC_RGBA_FLOAT:
854             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,4);
855             break;
856           case BC_YUV888:
857             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
858             break;
859           case BC_YUVA8888:
860             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
861             break;
862           }
863         }
864
865         /* ants */
866         if(show_ants){
867           for(j = 0; j < todo; j++){
868             float A = have_selection ? selection[j] : 1.f;
869             if(A>.99999f){
870               if( (ant+rowi-j)&0x4 ){
871                 /* magenta */
872                 Rvec[j] = 1;
873                 Gvec[j] = 0;
874                 Bvec[j] = 1;
875               }else{
876                 /* green */
877                 Rvec[j] = 0;
878                 Gvec[j] = 1;
879                 Bvec[j] = 0;
880               }
881             }else{
882               if( (ant+rowi+j)&0x4 ){
883                 /* black */
884                 Rvec[j] = 0;
885                 Gvec[j] = 0;
886                 Bvec[j] = 0;
887               }else{
888                 /* white */
889                 Rvec[j] = 1;
890                 Gvec[j] = 1;
891                 Bvec[j] = 1;
892               }
893             }
894           }
895
896           /* re-layer back into pipeline color format */
897           switch(frame->get_color_model()) {
898           case BC_RGB888:
899             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
900             break;
901           case BC_RGBA8888:
902             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
903             break;
904           case BC_RGB_FLOAT:
905             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,3);
906             break;
907           case BC_RGBA_FLOAT:
908             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,4);
909             break;
910           case BC_YUV888:
911             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
912             break;
913           case BC_YUVA8888:
914             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
915             break;
916           }
917         }
918
919         if(active || show_ants || (use_mask && capture_mask)){
920
921           if(use_mask && capture_mask){
922             switch(frame->get_color_model()) {
923             case BC_RGBA8888:
924               unmask_rgba8(row_fragment,todo);
925               break;
926             case BC_RGBA_FLOAT:
927               unmask_rgbaF((float *)row_fragment,todo);
928               break;
929             case BC_YUVA8888:
930               unmask_yuva8(row_fragment,todo);
931               break;
932             }
933           }
934
935           /* lock to prevent interleaved cache coherency collisions
936              across cores. Two memcpys touching the same cache line
937              will cause the wings to fall off the processor. */
938
939           pthread_mutex_lock(&engine->copylock);
940           memcpy(row,row_fragment,byte_advance);
941           pthread_mutex_unlock(&engine->copylock);
942           row+=byte_advance;
943
944         }
945       }
946     }
947   }
948
949   pthread_mutex_lock(&engine->copylock);
950
951   plugin->hue_total+=Htotal;
952   plugin->hue_weight+=Hweight;
953
954   for(int i=0;i<HISTSIZE;i++){
955     plugin->red_histogram[i] += Rhist[i];
956     plugin->green_histogram[i] += Ghist[i];
957     plugin->blue_histogram[i] += Bhist[i];
958
959     plugin->hue_histogram[i] += Hhist[i];
960     plugin->sat_histogram[i] += Shist[i];
961
962     plugin->value_histogram[i] += Vhist[i];
963   }
964
965   for(int i=0;i<(HISTSIZE>>HRGBSHIFT);i++){
966     plugin->hue_histogram_red[i] += Hhr[i];
967     plugin->hue_histogram_green[i] += Hhg[i];
968     plugin->hue_histogram_blue[i] += Hhb[i];
969
970     plugin->sat_histogram_red[i] += Shr[i];
971     plugin->sat_histogram_green[i] += Shg[i];
972     plugin->sat_histogram_blue[i] += Shb[i];
973
974     plugin->value_histogram_red[i] += Vhr[i];
975     plugin->value_histogram_green[i] += Vhg[i];
976     plugin->value_histogram_blue[i] += Vhb[i];
977   }
978   pthread_mutex_unlock(&engine->copylock);
979
980 }
981
982 BluebananaEngine::BluebananaEngine(BluebananaMain *plugin, int total_clients,
983                                    int total_packages) : LoadServer(total_clients, total_packages){
984   this->plugin = plugin;
985   selection_workA=0;
986   selection_workB=0;
987   task_init_serial=0;
988   pthread_mutex_init(&copylock,NULL);
989   pthread_mutex_init(&tasklock,NULL);
990   pthread_cond_init(&taskcond,NULL);
991 }
992 BluebananaEngine::~BluebananaEngine(){
993   pthread_cond_destroy(&taskcond);
994   pthread_mutex_destroy(&tasklock);
995   pthread_mutex_destroy(&copylock);
996   if(selection_workA) delete[] selection_workA;
997   if(selection_workB) delete[] selection_workB;
998 }
999
1000 void BluebananaEngine::init_packages(){}
1001
1002 LoadClient* BluebananaEngine::new_client(){
1003   return new BluebananaUnit(this, plugin);
1004 }
1005
1006 LoadPackage* BluebananaEngine::new_package(){
1007   return new BluebananaPackage(this);
1008 }
1009
1010 static float lt(float *data,float pos, int n){
1011   if(pos<0)pos+=n;
1012   if(pos>=n)pos-=n;
1013   int i = (int)pos;
1014   float del = pos-i;
1015   return data[i]*(1.f-del) + data[i+1]*del;
1016 }
1017
1018 static float lt_shift(float *data, float pos, int n, int over){
1019   float s0=0, s1=0;
1020   if(pos<0)pos+=n;
1021   if(pos>=n)pos-=n;
1022   int i = (int)pos;
1023   float del = pos-i;
1024   i *= over;
1025   data += i;
1026   for(int j=0; j<over; j++)
1027     s0 += *data++;
1028   for(int j=0; j<over; j++)
1029     s1 += *data++;
1030
1031   float temp=(s0*(1.f-del) + s1*del);
1032   if(temp>0)
1033     return 1./temp;
1034   else
1035     return 0;
1036 }
1037
1038 void BluebananaEngine::process_packages(VFrame *data){
1039   int w = data->get_w();
1040   int h = data->get_h();
1041   this->data = data;
1042   task_init_state=0;
1043   task_n=0;
1044   task_finish_count=0;
1045
1046   /* If we're doing any spatial modification of the selection, we'll
1047      need to operate on a temporary selection array that covers the
1048      complete frame */
1049   if(plugin->config.Fsel_active){
1050     if(plugin->config.Fsel_lo ||
1051        plugin->config.Fsel_mid ||
1052        plugin->config.Fsel_hi ||
1053        plugin->config.Fsel_over){
1054       selection_workA = new float[w*h];
1055       selection_workB = new float[w*h];
1056     }
1057   }
1058
1059   memset(plugin->red_histogram,0,sizeof(plugin->red_histogram));
1060   memset(plugin->green_histogram,0,sizeof(plugin->green_histogram));
1061   memset(plugin->blue_histogram,0,sizeof(plugin->blue_histogram));
1062   memset(plugin->hue_histogram,0,sizeof(plugin->hue_histogram));
1063   plugin->hue_total=0.f;
1064   plugin->hue_weight=0.f;
1065   memset(plugin->sat_histogram,0,sizeof(plugin->sat_histogram));
1066   memset(plugin->value_histogram,0,sizeof(plugin->value_histogram));
1067
1068   memset(plugin->hue_histogram_red,0,sizeof(plugin->hue_histogram_red));
1069   memset(plugin->hue_histogram_green,0,sizeof(plugin->hue_histogram_green));
1070   memset(plugin->hue_histogram_blue,0,sizeof(plugin->hue_histogram_blue));
1071
1072   memset(plugin->sat_histogram_red,0,sizeof(plugin->sat_histogram_red));
1073   memset(plugin->sat_histogram_green,0,sizeof(plugin->sat_histogram_green));
1074   memset(plugin->sat_histogram_blue,0,sizeof(plugin->sat_histogram_blue));
1075
1076   memset(plugin->value_histogram_red,0,sizeof(plugin->value_histogram_red));
1077   memset(plugin->value_histogram_green,0,sizeof(plugin->value_histogram_green));
1078   memset(plugin->value_histogram_blue,0,sizeof(plugin->value_histogram_blue));
1079
1080   LoadServer::process_packages();
1081
1082   /* The Hue histogram needs to be adjusted/shifted */
1083   if(plugin->config.active && plugin->hue_weight){
1084     int i,j;
1085     float scale = plugin->hue_total/plugin->hue_weight;
1086     float Hshift = plugin->config.Hsel_active ? (plugin->config.Hsel_lo + plugin->config.Hsel_hi)/720.f-.5f : 0.f;
1087     float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
1088     float hist[HISTSIZE + (1<<HRGBSHIFT)];
1089     float red[(HISTSIZE>>HRGBSHIFT)+1];
1090     float green[(HISTSIZE>>HRGBSHIFT)+1];
1091     float blue[(HISTSIZE>>HRGBSHIFT)+1];
1092
1093     for(i=0;i<(1<<HRGBSHIFT);i++){
1094       plugin->hue_histogram[i]+=plugin->hue_histogram[HISTSIZE+i];
1095       plugin->hue_histogram[HISTSIZE+i]=plugin->hue_histogram[i];
1096     }
1097     plugin->hue_histogram_red[0]+=plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT];
1098     plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_red[0];
1099     plugin->hue_histogram_green[0]+=plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT];
1100     plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_green[0];
1101     plugin->hue_histogram_blue[0]+=plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT];
1102     plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_blue[0];
1103
1104     for(i=0; i<(HISTSIZE>>HRGBSHIFT); i++){
1105       float pos = i+Hshift*(HISTSIZE>>HRGBSHIFT);
1106       if(pos<0)pos+=(HISTSIZE>>HRGBSHIFT);
1107       if(pos>=(HISTSIZE>>HRGBSHIFT))pos-=(HISTSIZE>>HRGBSHIFT);
1108
1109       float div = lt_shift(plugin->hue_histogram,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1110                            (HISTSIZE>>HRGBSHIFT), (1<<HRGBSHIFT));
1111       red[i] = lt(plugin->hue_histogram_red,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1112                   (HISTSIZE>>HRGBSHIFT))*div;
1113       green[i] = lt(plugin->hue_histogram_green,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1114                     (HISTSIZE>>HRGBSHIFT))*div;
1115       blue[i] = lt(plugin->hue_histogram_blue,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1116                    (HISTSIZE>>HRGBSHIFT))*div;
1117     }
1118
1119     for(int i=0; i<HISTSIZE; i++)
1120       hist[i] = lt(plugin->hue_histogram,i+Hshift*HISTSIZE,HISTSIZE)*scale;
1121
1122     memcpy(hist+HISTSIZE,hist,sizeof(*hist)*(1<<HRGBSHIFT));
1123     memcpy(plugin->hue_histogram,hist,sizeof(hist));
1124
1125     red[HISTSIZE>>HRGBSHIFT]=red[0];
1126     green[HISTSIZE>>HRGBSHIFT]=green[0];
1127     blue[HISTSIZE>>HRGBSHIFT]=blue[0];
1128
1129     for(i=0,j=0; i<=(HISTSIZE>>HRGBSHIFT); i++){
1130       float sum=0.f,H,S,V;
1131       for(int k=0; k<(1<<HRGBSHIFT); j++,k++)
1132         sum+=hist[j];
1133
1134       RGB_to_HSpV(red[i],green[i],blue[i],H,S,V);
1135       H+=Hal;
1136       if(H<0)H+=6;
1137       if(H>=6)H-=6;
1138       HSpV_to_RGB(H,S,V,red[i],green[i],blue[i]);
1139
1140       plugin->hue_histogram_red[i] = red[i] * sum;
1141       plugin->hue_histogram_green[i] = green[i] * sum;
1142       plugin->hue_histogram_blue[i] =  blue[i] * sum;
1143     }
1144   }
1145
1146   if(selection_workA){
1147     delete[] selection_workA;
1148     selection_workA=0;
1149   }
1150   if(selection_workB){
1151     delete[] selection_workB;
1152     selection_workB=0;
1153   }
1154 }
1155
1156 /* create a coordinated work-division list and join point */
1157 void BluebananaEngine::set_task(int n, const char *task){
1158   pthread_mutex_lock(&this->tasklock);
1159   if(task_init_state==0){
1160     //fprintf(stderr,"New task!: %s",task);
1161     task_n=n;
1162     task_finish_count=get_total_packages();
1163     task_init_state=1;
1164     task_init_serial++;
1165   }
1166   pthread_mutex_unlock(&this->tasklock);
1167 }
1168
1169 /* fetch the next task ticket.  If the task is complete, wait here for
1170    all package threads to complete before returning <0 */
1171 int BluebananaEngine::next_task(){
1172   pthread_mutex_lock(&tasklock);
1173   if(task_n){
1174     int ret = --task_n;
1175     //fprintf(stderr,".");
1176     pthread_mutex_unlock(&tasklock);
1177     return ret;
1178   }else{
1179     task_finish_count--;
1180     if(task_finish_count==0){
1181       task_init_state=0;
1182       //fprintf(stderr,"done\n");
1183       pthread_cond_broadcast(&taskcond);
1184     }else{
1185       int serial = task_init_serial;
1186       while(task_finish_count && serial == task_init_serial){
1187         //fprintf(stderr,"+");
1188         pthread_cond_wait(&taskcond,&tasklock);
1189       }
1190     }
1191     pthread_mutex_unlock(&tasklock);
1192     //fprintf(stderr,"-");
1193     return -1;
1194   }
1195 }
1196
1197 /* same as above, but waits for join without fetching a task slot */
1198 void BluebananaEngine::wait_task(){
1199   pthread_mutex_lock(&tasklock);
1200   task_finish_count--;
1201   if(task_finish_count==0){
1202     task_init_state=0;
1203     //fprintf(stderr,"done\n");
1204     pthread_cond_broadcast(&taskcond);
1205   }else{
1206     int serial = task_init_serial;
1207     while(task_finish_count && serial == task_init_serial){
1208       //fprintf(stderr,"+");
1209       pthread_cond_wait(&taskcond,&tasklock);
1210     }
1211   }
1212   pthread_mutex_unlock(&tasklock);
1213   //fprintf(stderr,"-");
1214 }