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