34037de1e25b9a52ec4bc07dce765da1e3b15abc
[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 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               /* we're using a mask; if the mask is set to capture, we
482                  need to restore alpha before skipping */
483               if(capture_mask){
484                 switch(frame->get_color_model()) {
485                 case BC_RGBA8888:
486                   unmask_rgba8(row_fragment,todo);
487                   break;
488                 case BC_RGBA_FLOAT:
489                   unmask_rgbaF((float *)row_fragment,todo);
490                   break;
491                 case BC_YUVA8888:
492                   unmask_yuva8(row_fragment,todo);
493                   break;
494                 }
495                 pthread_mutex_lock(&engine->copylock);
496                 memcpy(row,row_fragment,byte_advance);
497                 pthread_mutex_unlock(&engine->copylock);
498               }
499
500               row+=byte_advance;
501               continue;
502             }
503             if(selection_test > todo-SELECT_THRESH)
504               have_selection=0; // fully selected
505           }else{
506             if(have_selection){
507               if(invert_selection){
508                 if(selection_test < SELECT_THRESH){
509                   /* fully selected after inversion */
510                   selection_test=todo;
511                 }else if (selection_test >= todo-SELECT_THRESH){
512                   /* fully deselected after invert, skip fragment */
513                   row+=byte_advance;
514                   continue;
515                 }else{
516                   /* partial selection */
517                   selection_test=0.f;
518                   for(j = 0; j < todo; j++)
519                     selection_test += selection[j] = (1.f-selection[j]);
520                 }
521               }else{
522                 if(selection_test < SELECT_THRESH){
523                   /* fully deselected, skip fragment */
524                   row+=byte_advance;
525                   continue;
526                 }else if (selection_test >= todo-SELECT_THRESH){
527                   /* fully selected */
528                   selection_test=todo;
529                 }else{
530                   /* partial selection; already calculated */
531                 }
532               }
533               if(selection_test < SELECT_THRESH){
534                   row+=byte_advance;
535                   continue; // inactive fragment
536               }
537               if(selection_test > todo-SELECT_THRESH)
538                 have_selection=0; // fully selected
539             }else{
540               if(invert_selection){
541                   row+=byte_advance;
542                   continue;
543               }
544             }
545           }
546         }
547
548         if(active){
549
550           /* red adjust */
551           if(Ral) {
552             if(have_selection){
553               for(j = 0; j < todo; j++)
554                 if(selection[j]>SELECT_THRESH) Rvec[j]=adj_lookup(Rvec[j],Ral,Ras);
555             }else{
556               for(j = 0; j < todo; j++)
557                 Rvec[j] = adj_lookup(Rvec[j],Ral,Ras);
558             }
559           }
560           /* red histogram */
561           if(gui_open){
562             if(have_selection){
563               for(j = 0; j < todo; j++)
564                 if(selection[j]>SELECT_THRESH) Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
565             }else{
566               for(j = 0; j < todo; j++)
567                 Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
568             }
569           }
570
571           /* green adjust */
572           if(Gal) {
573             if(have_selection){
574               for(j = 0; j < todo; j++)
575                 if(selection[j]>SELECT_THRESH) Gvec[j]=adj_lookup(Gvec[j],Gal,Gas);
576             }else{
577               for(j = 0; j < todo; j++)
578                 Gvec[j] = adj_lookup(Gvec[j],Gal,Gas);
579             }
580           }
581           /* green histogram */
582           if(gui_open){
583             if(have_selection){
584               for(j = 0; j < todo; j++)
585                 if(selection[j]>SELECT_THRESH) Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
586             }else{
587               for(j = 0; j < todo; j++)
588                 Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
589             }
590           }
591
592           /* blue adjust */
593           if(Bal) {
594             if(have_selection){
595               for(j = 0; j < todo; j++)
596                 if(selection[j]>SELECT_THRESH) Bvec[j]=adj_lookup(Bvec[j],Bal,Bas);
597             }else{
598               for(j = 0; j < todo; j++)
599                 Bvec[j] = adj_lookup(Bvec[j],Bal,Bas);
600             }
601           }
602           /* blue histogram */
603           if(gui_open){
604             if(have_selection){
605               for(j = 0; j < todo; j++)
606                 if(selection[j]>SELECT_THRESH) Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
607             }else{
608               for(j = 0; j < todo; j++)
609                 Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
610             }
611           }
612
613           /* compute HSV values or update values from earlier selection work if
614              they've changed */
615           if( (!doSEL || doRGB) && // not yet computed, or since modified
616               (doHSV || gui_open) ) // needed for HSV mod and/or histograms
617             for(j = 0; j < todo; j++)
618               RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
619
620           if(doHSV){
621             /* H modification */
622             /* don't bother checking selection, H adj is lightweight */
623             if(Hal){
624               for(j = 0; j < todo; j++){
625                 Hvec[j] += Hal;
626                 if(Hvec[j]<0.f)Hvec[j]+=6.f;
627                 if(Hvec[j]>=6.f)Hvec[j]-=6.f;
628               }
629             }
630             /* H histogram */
631             /* this is pre-shift RGB data; shift hue later to save an HSV->RGB transform */
632             if(gui_open){
633               if(have_selection){
634                 for(j = 0; j < todo; j++){
635                   if(selection[j]>SELECT_THRESH){
636                     float weight = selection[j]*Svec[j];
637                     int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
638                     Htotal += selection[j];
639                     Hweight += weight;
640                     Hhist[bin] += weight;
641                     Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
642                     Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
643                     Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
644                   }
645                 }
646               }else{
647                 for(j = 0; j < todo; j++){
648                   float weight = Svec[j];
649                   int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
650                   Htotal += 1.f;
651                   Hweight += weight;
652                   Hhist[bin] += weight;
653                   Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
654                   Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
655                   Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
656                 }
657               }
658             }
659
660             /* S modification */
661             if(Sal) {
662               if(have_selection){
663                 for(j = 0; j < todo; j++)
664                   if(selection[j]>SELECT_THRESH) Svec[j] = adj_lookup(Svec[j],Sal,Sas);
665               }else{
666                 for(j = 0; j < todo; j++)
667                   Svec[j] = adj_lookup(Svec[j],Sal,Sas);
668               }
669             }
670
671             /* This is unrolled a few times below...
672                Although we're using HSV, we don't want hue/saturation
673                changes to have a strong effect on apparent brightness.
674                Apply a correction to V (not Y!) based on luma change. */
675             /* Calculate new RGB values at same time */
676             if(Hal || Sal){
677               if(have_selection){
678                 for(j = 0; j < todo; j++){
679                   if(selection[j]>SELECT_THRESH){
680                     HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
681                     /* run S histogram at the same time as we've got
682                        the RGB data */
683                     if(gui_open){
684                       int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
685                       Shist[bin] += selection[j];
686                       Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
687                       Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
688                       Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
689                     }
690                   }
691                 }
692               }else{
693                 for(j = 0; j < todo; j++){
694                   HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
695                   if(gui_open){
696                     int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
697                     Shist[bin] += 1.f;
698                     Shr[bin>>HRGBSHIFT] += Rvec[j];
699                     Shg[bin>>HRGBSHIFT] += Gvec[j];
700                     Shb[bin>>HRGBSHIFT] += Bvec[j];
701                   }
702                 }
703               }
704             }else{
705               if(gui_open){
706                 if(have_selection){
707                   for(j = 0; j < todo; j++){
708                     if(selection[j]>SELECT_THRESH){
709                       int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
710                       Shist[bin] += selection[j];
711                       Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
712                       Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
713                       Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
714                     }
715                   }
716                 }else{
717                   for(j = 0; j < todo; j++){
718                     int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
719                     Shist[bin] += 1.f;
720                     Shr[bin>>HRGBSHIFT] += Rvec[j];
721                     Shg[bin>>HRGBSHIFT] += Gvec[j];
722                     Shb[bin>>HRGBSHIFT] += Bvec[j];
723                   }
724                 }
725               }
726             }
727
728             /* V modification */
729             /* This one is a bit unlike the others; Value gamma
730                behavior is conditional.  When < 1.0 (darkening the
731                picture) gamma directly operates on Value as normally
732                expected (thus scaling R G and B about zero).  When
733                gamma > 1.0 (lightening the picture) it operates on the
734                Value scale's zero point rather than the Value.  Both
735                are done to get the most natural behavior out of
736                saturation as gamma changes.  The only drawback: One
737                can no longer reverse a gamma operation by applying the
738                inverse gamma in a subsequent step. */
739             if(Val){
740               if(have_selection){
741                 if(Vgamma<1.0){
742                   /* scale mode */
743                   for(j = 0; j < todo; j++)
744                     if(selection[j]>SELECT_THRESH){
745                       float scale = adj_lookup(Vvec[j],Val,Vas);
746                       Vvec[j] = Vvec[j] * scale + Vshift;
747                       Rvec[j] = Rvec[j] * scale + Vshift;
748                       Gvec[j] = Gvec[j] * scale + Vshift;
749                       Bvec[j] = Bvec[j] * scale + Vshift;
750                     }
751                 }else{
752                   /* shift mode */
753                   for(j = 0; j < todo; j++)
754                     if(selection[j]>SELECT_THRESH){
755                       float shift = adj_lookup(Vvec[j],Val,Vas);
756                       Vvec[j] = Vvec[j] * Vscale + shift;
757                       Rvec[j] = Rvec[j] * Vscale + shift;
758                       Gvec[j] = Gvec[j] * Vscale + shift;
759                       Bvec[j] = Bvec[j] * Vscale + shift;
760                     }
761                 }
762               }else{
763                 if(Vgamma<1.0){
764                   /* scale mode */
765                   for(j = 0; j < todo; j++){
766                     float scale = adj_lookup(Vvec[j],Val,Vas);
767                     Vvec[j] = Vvec[j] * scale + Vshift;
768                     Rvec[j] = Rvec[j] * scale + Vshift;
769                     Gvec[j] = Gvec[j] * scale + Vshift;
770                     Bvec[j] = Bvec[j] * scale + Vshift;
771                   }
772                 }else{
773                   /* shift mode */
774                   for(j = 0; j < todo; j++){
775                     float shift = adj_lookup(Vvec[j],Val,Vas);
776                     Vvec[j] = Vvec[j] * Vscale + shift;
777                     Rvec[j] = Rvec[j] * Vscale + shift;
778                     Gvec[j] = Gvec[j] * Vscale + shift;
779                     Bvec[j] = Bvec[j] * Vscale + shift;
780                   }
781                 }
782               }
783             }
784
785             /* V histogram */
786             if(gui_open){
787               if(have_selection){
788                 for(j = 0; j < todo; j++){
789                   if(selection[j]>SELECT_THRESH){
790                     int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
791                     Vhist[bin] += selection[j];
792                     Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
793                     Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
794                     Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
795                   }
796                 }
797               }else{
798                 for(j = 0; j < todo; j++){
799                   int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
800                   Vhist[bin] += 1.f;
801                   Vhr[bin>>HRGBSHIFT] += Rvec[j];
802                   Vhg[bin>>HRGBSHIFT] += Gvec[j];
803                   Vhb[bin>>HRGBSHIFT] += Bvec[j];
804                 }
805               }
806             }
807
808           }else if (gui_open){
809
810             if(have_selection){
811               /* H histogram */
812               for(j = 0; j < todo; j++){
813                 if(selection[j]>SELECT_THRESH){
814                   float weight = selection[j]*Svec[j];
815                   int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
816                   Htotal += selection[j];
817                   Hweight += weight;
818                   Hhist[bin] += weight;
819                   Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
820                   Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
821                   Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
822                 }
823               }
824               /* S histogram */
825               for(j = 0; j < todo; j++){
826                 if(selection[j]>SELECT_THRESH){
827                   int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
828                   Shist[bin] += selection[j];
829                   Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
830                   Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
831                   Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
832                 }
833               }
834               /* V histogram */
835               for(j = 0; j < todo; j++){
836                 if(selection[j]>SELECT_THRESH){
837                   int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
838                   Vhist[bin] += selection[j];
839                   Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
840                   Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
841                   Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
842                 }
843               }
844             }else{
845
846               /* H histogram */
847               for(j = 0; j < todo; j++){
848                 float weight = Svec[j];
849                 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
850                 Htotal += 1.f;
851                 Hweight += weight;
852                 Hhist[bin] += weight;
853                 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
854                 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
855                 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
856               }
857               /* S histogram */
858               for(j = 0; j < todo; j++){
859                 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
860                 Shist[bin] += 1.f;
861                 Shr[bin>>HRGBSHIFT] += Rvec[j];
862                 Shg[bin>>HRGBSHIFT] += Gvec[j];
863                 Shb[bin>>HRGBSHIFT] += Bvec[j];
864               }
865               /* V histogram */
866               for(j = 0; j < todo; j++){
867                 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
868                 Vhist[bin] += 1.f;
869                 Vhr[bin>>HRGBSHIFT] += Rvec[j];
870                 Vhg[bin>>HRGBSHIFT] += Gvec[j];
871                 Vhb[bin>>HRGBSHIFT] += Bvec[j];
872               }
873             }
874           }
875
876           /* layer back into pipeline color format; master fader applies here */
877           switch(frame->get_color_model()) {
878           case BC_RGB888:
879             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,row_fragment,todo,3);
880             break;
881           case BC_RGBA8888:
882             RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,row_fragment,todo,4);
883             break;
884           case BC_RGB_FLOAT:
885             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,(float *)row_fragment,todo,3);
886             break;
887           case BC_RGBA_FLOAT:
888             RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,(float *)row_fragment,todo,4);
889             break;
890           case BC_YUV888:
891             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,row_fragment,todo,3);
892             break;
893           case BC_YUVA8888:
894             RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Oal,row_fragment,todo,4);
895             break;
896           }
897         }
898
899         /* ants */
900         if(show_ants){
901           for(j = 0; j < todo; j++){
902             float A = have_selection ? selection[j] : 1.f;
903             if(A>.99999f){
904               if( (ant+rowi-j)&0x4 ){
905                 /* magenta */
906                 Rvec[j] = 1;
907                 Gvec[j] = 0;
908                 Bvec[j] = 1;
909               }else{
910                 /* green */
911                 Rvec[j] = 0;
912                 Gvec[j] = 1;
913                 Bvec[j] = 0;
914               }
915             }else{
916               if( (ant+rowi+j)&0x4 ){
917                 /* black */
918                 Rvec[j] = 0;
919                 Gvec[j] = 0;
920                 Bvec[j] = 0;
921               }else{
922                 /* white */
923                 Rvec[j] = 1;
924                 Gvec[j] = 1;
925                 Bvec[j] = 1;
926               }
927             }
928           }
929           float *s = have_selection?selection:0;
930           /* re-layer back into pipeline color format */
931           switch(frame->get_color_model()) {
932           case BC_RGB888:
933             RGB_to_rgb8(Rvec,Gvec,Bvec,s,1.f,row_fragment,todo,3);
934             break;
935           case BC_RGBA8888:
936             RGB_to_rgb8(Rvec,Gvec,Bvec,s,1.f,row_fragment,todo,4);
937             break;
938           case BC_RGB_FLOAT:
939             RGB_to_rgbF(Rvec,Gvec,Bvec,s,1.f,(float *)row_fragment,todo,3);
940             break;
941           case BC_RGBA_FLOAT:
942             RGB_to_rgbF(Rvec,Gvec,Bvec,s,1.f,(float *)row_fragment,todo,4);
943             break;
944           case BC_YUV888:
945             RGB_to_yuv8(Rvec,Gvec,Bvec,s,1.f,row_fragment,todo,3);
946             break;
947           case BC_YUVA8888:
948             RGB_to_yuv8(Rvec,Gvec,Bvec,s,1.f,row_fragment,todo,4);
949             break;
950           }
951         }
952
953         if(active || show_ants || use_mask || capture_mask){
954           if(capture_mask){
955             switch(frame->get_color_model()) {
956             case BC_RGBA8888:
957               unmask_rgba8(row_fragment,todo);
958               break;
959             case BC_RGBA_FLOAT:
960               unmask_rgbaF((float *)row_fragment,todo);
961               break;
962             case BC_YUVA8888:
963               unmask_yuva8(row_fragment,todo);
964               break;
965             }
966           }
967           else if(use_mask){
968             float *s = !show_ants&&have_selection?selection:0;
969             switch(frame->get_color_model()) {
970             case BC_RGBA8888:
971             case BC_YUVA8888:
972               Aal_to_alp8(s,Aal,row_fragment,todo,4);
973               break;
974             case BC_RGBA_FLOAT:
975               Aal_to_alpF(s,Aal,(float *)row_fragment,todo,4);
976               break;
977             }
978           }
979
980           /* lock to prevent interleaved cache coherency collisions
981              across cores. Two memcpys touching the same cache line
982              will cause the wings to fall off the processor. */
983
984           pthread_mutex_lock(&engine->copylock);
985           memcpy(row,row_fragment,byte_advance);
986           pthread_mutex_unlock(&engine->copylock);
987           row+=byte_advance;
988
989         }
990       }
991     }
992   }
993
994   pthread_mutex_lock(&engine->copylock);
995
996   plugin->hue_total+=Htotal;
997   plugin->hue_weight+=Hweight;
998
999   for(int i=0;i<HISTSIZE;i++){
1000     plugin->red_histogram[i] += Rhist[i];
1001     plugin->green_histogram[i] += Ghist[i];
1002     plugin->blue_histogram[i] += Bhist[i];
1003
1004     plugin->hue_histogram[i] += Hhist[i];
1005     plugin->sat_histogram[i] += Shist[i];
1006
1007     plugin->value_histogram[i] += Vhist[i];
1008   }
1009
1010   for(int i=0;i<(HISTSIZE>>HRGBSHIFT);i++){
1011     plugin->hue_histogram_red[i] += Hhr[i];
1012     plugin->hue_histogram_green[i] += Hhg[i];
1013     plugin->hue_histogram_blue[i] += Hhb[i];
1014
1015     plugin->sat_histogram_red[i] += Shr[i];
1016     plugin->sat_histogram_green[i] += Shg[i];
1017     plugin->sat_histogram_blue[i] += Shb[i];
1018
1019     plugin->value_histogram_red[i] += Vhr[i];
1020     plugin->value_histogram_green[i] += Vhg[i];
1021     plugin->value_histogram_blue[i] += Vhb[i];
1022   }
1023   pthread_mutex_unlock(&engine->copylock);
1024
1025 }
1026
1027 BluebananaEngine::BluebananaEngine(BluebananaMain *plugin, int total_clients,
1028                                    int total_packages) : LoadServer(total_clients, total_packages){
1029   this->plugin = plugin;
1030   selection_workA=0;
1031   selection_workB=0;
1032   task_init_serial=0;
1033   pthread_mutex_init(&copylock,NULL);
1034   pthread_mutex_init(&tasklock,NULL);
1035   pthread_cond_init(&taskcond,NULL);
1036 }
1037 BluebananaEngine::~BluebananaEngine(){
1038   pthread_cond_destroy(&taskcond);
1039   pthread_mutex_destroy(&tasklock);
1040   pthread_mutex_destroy(&copylock);
1041   if(selection_workA) delete[] selection_workA;
1042   if(selection_workB) delete[] selection_workB;
1043 }
1044
1045 void BluebananaEngine::init_packages(){}
1046
1047 LoadClient* BluebananaEngine::new_client(){
1048   return new BluebananaUnit(this, plugin);
1049 }
1050
1051 LoadPackage* BluebananaEngine::new_package(){
1052   return new BluebananaPackage(this);
1053 }
1054
1055 static float lt(float *data,float pos, int n){
1056   if(pos<0)pos+=n;
1057   if(pos>=n)pos-=n;
1058   int i = (int)pos;
1059   float del = pos-i;
1060   return data[i]*(1.f-del) + data[i+1]*del;
1061 }
1062
1063 static float lt_shift(float *data, float pos, int n, int over){
1064   float s0=0, s1=0;
1065   if(pos<0)pos+=n;
1066   if(pos>=n)pos-=n;
1067   int i = (int)pos;
1068   float del = pos-i;
1069   i *= over;
1070   data += i;
1071   for(int j=0; j<over; j++)
1072     s0 += *data++;
1073   for(int j=0; j<over; j++)
1074     s1 += *data++;
1075
1076   float temp=(s0*(1.f-del) + s1*del);
1077   if(temp>0)
1078     return 1./temp;
1079   else
1080     return 0;
1081 }
1082
1083 void BluebananaEngine::process_packages(VFrame *data){
1084   int w = data->get_w();
1085   int h = data->get_h();
1086   this->data = data;
1087   task_init_state=0;
1088   task_n=0;
1089   task_finish_count=0;
1090
1091   /* If we're doing any spatial modification of the selection, we'll
1092      need to operate on a temporary selection array that covers the
1093      complete frame */
1094   if(plugin->config.Fsel_active){
1095     if(plugin->config.Fsel_lo ||
1096        plugin->config.Fsel_mid ||
1097        plugin->config.Fsel_hi ||
1098        plugin->config.Fsel_over){
1099       selection_workA = new float[w*h];
1100       selection_workB = new float[w*h];
1101     }
1102   }
1103
1104   memset(plugin->red_histogram,0,sizeof(plugin->red_histogram));
1105   memset(plugin->green_histogram,0,sizeof(plugin->green_histogram));
1106   memset(plugin->blue_histogram,0,sizeof(plugin->blue_histogram));
1107   memset(plugin->hue_histogram,0,sizeof(plugin->hue_histogram));
1108   plugin->hue_total=0.f;
1109   plugin->hue_weight=0.f;
1110   memset(plugin->sat_histogram,0,sizeof(plugin->sat_histogram));
1111   memset(plugin->value_histogram,0,sizeof(plugin->value_histogram));
1112
1113   memset(plugin->hue_histogram_red,0,sizeof(plugin->hue_histogram_red));
1114   memset(plugin->hue_histogram_green,0,sizeof(plugin->hue_histogram_green));
1115   memset(plugin->hue_histogram_blue,0,sizeof(plugin->hue_histogram_blue));
1116
1117   memset(plugin->sat_histogram_red,0,sizeof(plugin->sat_histogram_red));
1118   memset(plugin->sat_histogram_green,0,sizeof(plugin->sat_histogram_green));
1119   memset(plugin->sat_histogram_blue,0,sizeof(plugin->sat_histogram_blue));
1120
1121   memset(plugin->value_histogram_red,0,sizeof(plugin->value_histogram_red));
1122   memset(plugin->value_histogram_green,0,sizeof(plugin->value_histogram_green));
1123   memset(plugin->value_histogram_blue,0,sizeof(plugin->value_histogram_blue));
1124
1125   LoadServer::process_packages();
1126
1127   /* The Hue histogram needs to be adjusted/shifted */
1128   if(plugin->config.active && plugin->hue_weight){
1129     int i,j;
1130     float scale = plugin->hue_total/plugin->hue_weight;
1131     float Hshift = plugin->config.Hsel_active ? (plugin->config.Hsel_lo + plugin->config.Hsel_hi)/720.f-.5f : 0.f;
1132     float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
1133     float hist[HISTSIZE + (1<<HRGBSHIFT)];
1134     float red[(HISTSIZE>>HRGBSHIFT)+1];
1135     float green[(HISTSIZE>>HRGBSHIFT)+1];
1136     float blue[(HISTSIZE>>HRGBSHIFT)+1];
1137
1138     for(i=0;i<(1<<HRGBSHIFT);i++){
1139       plugin->hue_histogram[i]+=plugin->hue_histogram[HISTSIZE+i];
1140       plugin->hue_histogram[HISTSIZE+i]=plugin->hue_histogram[i];
1141     }
1142     plugin->hue_histogram_red[0]+=plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT];
1143     plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_red[0];
1144     plugin->hue_histogram_green[0]+=plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT];
1145     plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_green[0];
1146     plugin->hue_histogram_blue[0]+=plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT];
1147     plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_blue[0];
1148
1149     for(i=0; i<(HISTSIZE>>HRGBSHIFT); i++){
1150       float pos = i+Hshift*(HISTSIZE>>HRGBSHIFT);
1151       if(pos<0)pos+=(HISTSIZE>>HRGBSHIFT);
1152       if(pos>=(HISTSIZE>>HRGBSHIFT))pos-=(HISTSIZE>>HRGBSHIFT);
1153
1154       float div = lt_shift(plugin->hue_histogram,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1155                            (HISTSIZE>>HRGBSHIFT), (1<<HRGBSHIFT));
1156       red[i] = lt(plugin->hue_histogram_red,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1157                   (HISTSIZE>>HRGBSHIFT))*div;
1158       green[i] = lt(plugin->hue_histogram_green,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1159                     (HISTSIZE>>HRGBSHIFT))*div;
1160       blue[i] = lt(plugin->hue_histogram_blue,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1161                    (HISTSIZE>>HRGBSHIFT))*div;
1162     }
1163
1164     for(int i=0; i<HISTSIZE; i++)
1165       hist[i] = lt(plugin->hue_histogram,i+Hshift*HISTSIZE,HISTSIZE)*scale;
1166
1167     memcpy(hist+HISTSIZE,hist,sizeof(*hist)*(1<<HRGBSHIFT));
1168     memcpy(plugin->hue_histogram,hist,sizeof(hist));
1169
1170     red[HISTSIZE>>HRGBSHIFT]=red[0];
1171     green[HISTSIZE>>HRGBSHIFT]=green[0];
1172     blue[HISTSIZE>>HRGBSHIFT]=blue[0];
1173
1174     for(i=0,j=0; i<=(HISTSIZE>>HRGBSHIFT); i++){
1175       float sum=0.f,H,S,V;
1176       for(int k=0; k<(1<<HRGBSHIFT); j++,k++)
1177         sum+=hist[j];
1178
1179       RGB_to_HSpV(red[i],green[i],blue[i],H,S,V);
1180       H+=Hal;
1181       if(H<0)H+=6;
1182       if(H>=6)H-=6;
1183       HSpV_to_RGB(H,S,V,red[i],green[i],blue[i]);
1184
1185       plugin->hue_histogram_red[i] = red[i] * sum;
1186       plugin->hue_histogram_green[i] = green[i] * sum;
1187       plugin->hue_histogram_blue[i] =  blue[i] * sum;
1188     }
1189   }
1190
1191   if(selection_workA){
1192     delete[] selection_workA;
1193     selection_workA=0;
1194   }
1195   if(selection_workB){
1196     delete[] selection_workB;
1197     selection_workB=0;
1198   }
1199 }
1200
1201 /* create a coordinated work-division list and join point */
1202 void BluebananaEngine::set_task(int n, const char *task){
1203   pthread_mutex_lock(&this->tasklock);
1204   if(task_init_state==0){
1205     //fprintf(stderr,"New task!: %s",task);
1206     task_n=n;
1207     task_finish_count=get_total_packages();
1208     task_init_state=1;
1209     task_init_serial++;
1210   }
1211   pthread_mutex_unlock(&this->tasklock);
1212 }
1213
1214 /* fetch the next task ticket.  If the task is complete, wait here for
1215    all package threads to complete before returning <0 */
1216 int BluebananaEngine::next_task(){
1217   pthread_mutex_lock(&tasklock);
1218   if(task_n){
1219     int ret = --task_n;
1220     //fprintf(stderr,".");
1221     pthread_mutex_unlock(&tasklock);
1222     return ret;
1223   }else{
1224     task_finish_count--;
1225     if(task_finish_count==0){
1226       task_init_state=0;
1227       //fprintf(stderr,"done\n");
1228       pthread_cond_broadcast(&taskcond);
1229     }else{
1230       int serial = task_init_serial;
1231       while(task_finish_count && serial == task_init_serial){
1232         //fprintf(stderr,"+");
1233         pthread_cond_wait(&taskcond,&tasklock);
1234       }
1235     }
1236     pthread_mutex_unlock(&tasklock);
1237     //fprintf(stderr,"-");
1238     return -1;
1239   }
1240 }
1241
1242 /* same as above, but waits for join without fetching a task slot */
1243 void BluebananaEngine::wait_task(){
1244   pthread_mutex_lock(&tasklock);
1245   task_finish_count--;
1246   if(task_finish_count==0){
1247     task_init_state=0;
1248     //fprintf(stderr,"done\n");
1249     pthread_cond_broadcast(&taskcond);
1250   }else{
1251     int serial = task_init_serial;
1252     while(task_finish_count && serial == task_init_serial){
1253       //fprintf(stderr,"+");
1254       pthread_cond_wait(&taskcond,&tasklock);
1255     }
1256   }
1257   pthread_mutex_unlock(&tasklock);
1258   //fprintf(stderr,"-");
1259 }