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