rework histogram_bezier, init wm icon set_icon(gg), update de.po+msg/txt
[goodguy/history.git] / cinelerra-5.1 / plugins / histogram_bezier / bistogram.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <math.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "bcdisplayinfo.h"
28 #include "bcsignals.h"
29 #include "clip.h"
30 #include "bchash.h"
31 #include "filexml.h"
32 #include "bistogram.h"
33 #include "bistogramconfig.h"
34 #include "bistogramwindow.h"
35 #include "keyframe.h"
36 #include "language.h"
37 #include "loadbalance.h"
38 #include "bccolors.h"
39 #include "vframe.h"
40
41
42
43 class HistogramMain;
44 class HistogramEngine;
45 class HistogramWindow;
46
47 REGISTER_PLUGIN(HistogramMain)
48
49 HistogramMain::HistogramMain(PluginServer *server)
50  : PluginVClient(server)
51 {
52         engine = 0;
53         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
54                 lookup[i] = 0;
55                 smoothed[i] = 0;
56                 linear[i] = 0;
57                 accum[i] = 0;
58         }
59         current_point = -1;
60         mode = HISTOGRAM_VALUE;
61         dragging_point = 0;
62         input = 0;
63         output = 0;
64         slots = 0;
65 }
66
67 HistogramMain::~HistogramMain()
68 {
69         reset();
70 }
71
72 void HistogramMain::reset()
73 {
74         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
75                 delete [] lookup[i];    lookup[i] = 0;
76                 delete [] smoothed[i];  smoothed[i] = 0;
77                 delete [] linear[i];    linear[i] = 0;
78                 delete [] accum[i];     accum[i] = 0;
79         }
80         delete engine;  engine = 0;
81         slots = 0;
82 }
83
84 const char* HistogramMain::plugin_title() { return N_("Histogram Bezier"); }
85 int HistogramMain::is_realtime() { return 1; }
86
87
88 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
89 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
90
91 void HistogramMain::render_gui(void *data)
92 {
93         if(thread)
94         {
95                 VFrame *input = (VFrame *)data;
96                 calculate_histogram(input);
97                 if( config.automatic )
98                         calculate_automatic(input);
99
100                 HistogramWindow *window = (HistogramWindow *)thread->window;
101                 window->lock_window("HistogramMain::render_gui");
102                 window->update_canvas();
103                 if(config.automatic)
104                 {
105                         window->update_input();
106                 }
107                 window->unlock_window();
108         }
109 }
110
111 void HistogramMain::update_gui()
112 {
113         if( !thread ) return;
114         HistogramWindow *window = (HistogramWindow *)thread->window;
115 // points delete in load_configuration,read_data
116         window->lock_window("HistogramMain::update_gui");
117         if( load_configuration() ) {
118                 window->update(0);
119                 if(!config.automatic)
120                         window->update_input();
121         }
122         window->unlock_window();
123 }
124
125
126 void HistogramMain::save_data(KeyFrame *keyframe)
127 {
128         FileXML output;
129
130 // cause data to be stored directly in text
131         output.set_shared_output(keyframe->xbuf);
132         output.tag.set_title("HISTOGRAM");
133
134         char string[BCTEXTLEN];
135
136
137         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
138                 sprintf(string, "OUTPUT_MIN_%d", i);
139                 output.tag.set_property(string, config.output_min[i]);
140                 sprintf(string, "OUTPUT_MAX_%d", i);
141                 output.tag.set_property(string, config.output_max[i]);
142 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
143         }
144
145         output.tag.set_property("AUTOMATIC", config.automatic);
146         output.tag.set_property("THRESHOLD", config.threshold);
147         output.tag.set_property("SPLIT", config.split);
148         output.tag.set_property("INTERPOLATION", config.smoothMode);
149         output.append_tag();
150         output.tag.set_title("/HISTOGRAM");
151         output.append_tag();
152         output.append_newline();
153
154
155
156
157
158         for( int j=0; j<HISTOGRAM_MODES; ++j ) {
159                 output.tag.set_title("POINTS");
160                 output.append_tag();
161                 output.append_newline();
162
163
164                 HistogramPoint *current = config.points[j].first;
165                 while( current ) {
166                         output.tag.set_title("POINT");
167                         output.tag.set_property("X", current->x);
168                         output.tag.set_property("Y", current->y);
169                         output.tag.set_property("GRADIENT", current->gradient);
170                         output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
171                         output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
172                         output.append_tag();
173                         output.tag.set_title("/POINT");
174                         output.append_tag();
175                         output.append_newline();
176                         current = NEXT;
177                 }
178
179
180                 output.tag.set_title("/POINTS");
181                 output.append_tag();
182                 output.append_newline();
183         }
184
185
186
187
188
189
190         output.terminate_string();
191 }
192
193 void HistogramMain::read_data(KeyFrame *keyframe)
194 {
195         FileXML input;
196
197         input.set_shared_input(keyframe->xbuf);
198
199         int result = 0;
200         int current_input_mode = 0;
201
202
203         while( !(result = input.read_tag()) ) {
204                 if( input.tag.title_is("HISTOGRAM") ) {
205                         char string[BCTEXTLEN];
206                         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
207                                 sprintf(string, "OUTPUT_MIN_%d", i);
208                                 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
209                                 sprintf(string, "OUTPUT_MAX_%d", i);
210                                 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
211 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
212                         }
213                         config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
214                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
215                         config.split = input.tag.get_property("SPLIT", config.split);
216                         config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
217                 }
218                 else if( input.tag.title_is("POINTS") ) {
219                         if( current_input_mode < HISTOGRAM_MODES ) {
220                                 HistogramPoints *points = &config.points[current_input_mode];
221                                 while( points->last )
222                                         delete points->last;
223                                 while( !(result = input.read_tag()) ) {
224                                         if( input.tag.title_is("/POINTS") ) break;
225                                         if(input.tag.title_is("POINT") ) {
226                                                 points->insert(
227                                                         input.tag.get_property("X", 0.0),
228                                                         input.tag.get_property("Y", 0.0));
229                                                 points->last->gradient =
230                                                         input.tag.get_property("GRADIENT", 1.0);
231                                                 points->last->xoffset_left =
232                                                         input.tag.get_property("XOFFSET_LEFT", -0.02);
233                                                 points->last->xoffset_right =
234                                                         input.tag.get_property("XOFFSET_RIGHT", 0.02);
235                                         }
236                                 }
237                                 ++current_input_mode;
238                         }
239                 }
240         }
241
242         config.boundaries();
243
244 }
245
246 float HistogramMain::calculate_linear(float input,
247         int subscript,
248         int use_value)
249 {
250         int done = 0;
251         float output;
252
253         if(input < 0) {
254                 output = 0;
255                 done = 1;
256         }
257
258         if(input > 1) {
259                 output = 1;
260                 done = 1;
261         }
262
263         if(!done) {
264
265                 float x1 = 0, y1 = 0;
266                 float grad1 = 1.0;
267                 float x1right = 0;
268                 float x2 = 1, y2 = 1;
269                 float grad2 = 1.0;
270                 float x2left = 0;
271
272 // Get 2 points surrounding current position
273                 HistogramPoints *points = &config.points[subscript];
274                 HistogramPoint *current = points->first;
275                 int done = 0;
276                 while( current && !done ) {
277                         if( current->x > input ) {
278                                 x2 = current->x;
279                                 y2 = current->y;
280                                 grad2 = current->gradient;
281                                 x2left = current->xoffset_left;
282                                 done = 1;
283                         }
284                         else
285                                 current = NEXT;
286                 }
287
288                 current = points->last;
289                 done = 0;
290                 while( current && !done ) {
291                         if( current->x <= input ) {
292                                 x1 = current->x;
293                                 y1 = current->y;
294                                 grad1 = current->gradient;
295                                 done = 1;
296                                 x1right = current->xoffset_right;
297                         }
298                         else
299                                 current = PREVIOUS;
300                 }
301
302                 if( !EQUIV(x2 - x1, 0) ) {
303                   if( config.smoothMode == HISTOGRAM_LINEAR )
304                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
305                   else if( config.smoothMode == HISTOGRAM_POLYNOMINAL ) {
306                         /* Construct third grade polynom between every two points */
307                         float dx = x2 - x1;
308                         float dy = y2 - y1;
309                         float delx = input - x1;
310                         output = (grad2 * dx + grad1 * dx - 2*dy) / (dx * dx * dx) * delx * delx * delx +
311                                 (3*dy - 2* grad1*dx - grad2*dx) / (dx * dx) * delx * delx + grad1*delx + y1;
312                   }
313                   else if( config.smoothMode == HISTOGRAM_BEZIER ) {
314                         /* Using standart DeCasteljau algorithm */
315                         float y1right = y1 + grad1 * x1right;
316                         float y2left = y2 + grad2 * x2left;
317
318                         float t = (input - x1) / (x2 - x1);
319
320                         float pointAy = y1 + (y1right - y1) * t;
321                         float pointBy = y1right + (y2left - y1right) * t;
322                         float pointCy = y2left + (y2 - y2left) * t;
323                         float pointABy = pointAy + (pointBy - pointAy) * t;
324                         float pointBCy = pointBy + (pointCy - pointBy) * t;
325                         output = pointABy + (pointBCy - pointABy) * t;
326                   }
327                 }
328                 else
329 // Linear
330                         output = input * y2;
331         }
332
333 // Apply value curve
334         if( use_value ) {
335                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
336         }
337
338
339         float output_min = config.output_min[subscript];
340         float output_max = config.output_max[subscript];
341
342 // Compress output for value followed by channel
343         output = output_min + output * (output_max - output_min);
344         return output;
345 }
346
347 float HistogramMain::calculate_smooth(float input, int subscript)
348 {
349         int bins = slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
350         int bins1 = bins-1;
351         float x_f = (input - HIST_MIN_INPUT) * bins / FLOAT_RANGE;
352         int x_i1 = (int)x_f;
353         int x_i2 = x_i1 + 1;
354         CLAMP(x_i1, 0, bins1);
355         CLAMP(x_i2, 0, bins1);
356         CLAMP(x_f, 0, bins1);
357
358         float smooth1 = smoothed[subscript][x_i1];
359         float smooth2 = smoothed[subscript][x_i2];
360         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
361         CLAMP(result, 0, 1.0);
362         return result;
363 }
364
365
366 void HistogramMain::calculate_histogram(VFrame *data)
367 {
368         int color_model = data->get_color_model();
369         int pix_sz = BC_CModels::calculate_pixelsize(color_model);
370         int comp_sz = pix_sz / BC_CModels::components(color_model);
371         int needed_slots = comp_sz > 1 ? 0x10000 : 0x100;
372         if( slots != needed_slots ) {
373                 reset();
374                 slots = needed_slots;
375         }
376         int bins = slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
377         if( !accum[0] ) {
378                 for( int i=0; i<HISTOGRAM_MODES; ++i )
379                         accum[i] = new int[bins];
380         }
381
382         if( !engine ) {
383                 int cpus = data->get_w() * data->get_h() * pix_sz / 0x80000 + 2;
384                 int smps = get_project_smp();
385                 if( cpus > smps ) cpus = smps;
386                 engine = new HistogramEngine(this, cpus, cpus);
387         }
388         engine->process_packages(HistogramEngine::HISTOGRAM, data);
389
390         for( int i=0; i<engine->get_total_clients(); ++i ) {
391                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
392                 if( i == 0 ) {
393                         for( int j=0; j<HISTOGRAM_MODES; ++j )
394                                 memcpy(accum[j], unit->accum[j], sizeof(int)*bins);
395                 }
396                 else {
397                         for( int j=0; j<HISTOGRAM_MODES; ++j ) {
398                                 int *out = accum[j], *in = unit->accum[j];
399                                 for( int k=0; k<bins; ++k ) out[k] += in[k];
400                         }
401                 }
402         }
403
404 // Remove top and bottom from calculations.  Doesn't work in high
405 // precision colormodels.
406         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
407                 accum[i][0] = 0;
408                 accum[i][bins-1] = 0;
409         }
410 }
411
412
413 void HistogramMain::calculate_automatic(VFrame *data)
414 {
415         calculate_histogram(data);
416         config.reset_points();
417         int bins = slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
418
419 // Do each channel
420         for( int i=0; i<3; ++i ) {
421                 int *accum = this->accum[i];
422                 int pixels = data->get_w() * data->get_h();
423                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
424                 int threshold = (int)(white_fraction * pixels);
425                 int total = 0;
426                 float max_level = 1.0;
427                 float min_level = 0.0;
428 // Get histogram slot above threshold of pixels
429                 for( int j=0; j<bins; ++j ) {
430                         total += accum[j];
431                         if( total >= threshold ) {
432                                 max_level = (float)j/bins * FLOAT_RANGE + HIST_MIN_INPUT;
433                                 break;
434                         }
435                 }
436
437 // Get slot below 99% of pixels
438                 total = 0;
439                 for( int j=bins; --j>=0; ) {
440                         total += accum[j];
441                         if( total >= threshold ) {
442                                 min_level = (float)j/bins * FLOAT_RANGE + HIST_MIN_INPUT;
443                                 break;
444                         }
445                 }
446                 config.points[i].insert(max_level, 1.0);
447                 config.points[i].insert(min_level, 0.0);
448         }
449 }
450
451 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
452 {
453         this->input = input_ptr;
454         this->output = output_ptr;
455
456         int need_reconfigure = load_configuration();
457         int color_model = input->get_color_model();
458         int pix_sz = BC_CModels::calculate_pixelsize(color_model);
459         int comp_sz = pix_sz / BC_CModels::components(color_model);
460         int needed_slots = comp_sz > 1 ? 0x10000 : 0x100;
461         if( slots != needed_slots ) {
462                 reset();
463                 slots = needed_slots;
464                 need_reconfigure = 1;
465         }
466
467         send_render_gui(input);
468
469         if( input->get_rows()[0] != output_ptr->get_rows()[0] ) {
470                 output_ptr->copy_from(input);
471         }
472
473 SET_TRACE
474 // Generate tables here.  The same table is used by many packages to render
475 // each horizontal stripe.  Need to cover the entire output range in  each
476 // table to avoid green borders
477         if( !lookup[0] || !smoothed[0] || !linear[0] || config.automatic)
478                 need_reconfigure = 1;
479         if( need_reconfigure ) {
480 SET_TRACE
481 // Calculate new curves
482                 if( config.automatic ) {
483                         calculate_automatic(input);
484                 }
485 SET_TRACE
486
487 // Generate transfer tables for integer colormodels.
488                 for( int i=0; i<3; ++i )
489                         tabulate_curve(i, 1);
490 SET_TRACE
491         }
492
493         if( !engine ) {
494                 int cpus = input->get_w() * input->get_h() * pix_sz / 0x80000 + 2;
495                 int smps = get_project_smp();
496                 if( cpus > smps ) cpus = smps;
497                 engine = new HistogramEngine(this, cpus, cpus);
498         }
499 // Apply histogram
500         engine->process_packages(HistogramEngine::APPLY, input);
501
502 SET_TRACE
503         return 0;
504 }
505
506 void HistogramMain::tabulate_curve(int subscript, int use_value)
507 {
508         int bins = slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
509         if(!lookup[subscript])
510                 lookup[subscript] = new int[bins];
511         if(!smoothed[subscript])
512                 smoothed[subscript] = new float[bins];
513         if(!linear[subscript])
514                 linear[subscript] = new float[bins];
515
516         float *current_smooth = smoothed[subscript];
517         float *current_linear = linear[subscript];
518
519 // Make linear curve
520         for( int i=0; i<bins; ++i ) {
521                 float input = (float)i/bins * FLOAT_RANGE + HIST_MIN_INPUT;
522                 current_linear[i] = calculate_linear(input, subscript, use_value);
523         }
524 // Make smooth curve
525         //float prev = 0.0;
526         for( int i=0; i<bins; ++i ) {
527 //              current_smooth[i] = current_linear[i] * 0.001 +
528 //                      prev * 0.999;
529                 current_smooth[i] = current_linear[i];
530 //              prev = current_smooth[i];
531         }
532 // Generate lookup tables for integer colormodels
533         if( input ) {
534                 int slots1 = slots-1;
535                 for( int i=0; i<slots; ++i ) {
536                         lookup[subscript][i] =
537                                 (int)(calculate_smooth((float)i/slots1, subscript) * slots1);
538                 }
539         }
540 }
541
542 HistogramPackage::HistogramPackage()
543  : LoadPackage()
544 {
545 }
546
547 HistogramUnit::HistogramUnit(HistogramEngine *server,
548         HistogramMain *plugin)
549  : LoadClient(server)
550 {
551         this->plugin = plugin;
552         this->server = server;
553         int bins = plugin->slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
554         for( int i=0; i<HISTOGRAM_MODES; ++i )
555                 accum[i] = new int[bins];
556 }
557
558 HistogramUnit::~HistogramUnit()
559 {
560         for( int i=0; i<HISTOGRAM_MODES; ++i )
561                 delete [] accum[i];
562 }
563
564 void HistogramUnit::process_package(LoadPackage *package)
565 {
566         HistogramPackage *pkg = (HistogramPackage*)package;
567         int bins = plugin->slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
568         int bins1 = bins-1;
569         int slots1 = -HISTOGRAM_MIN * (plugin->slots-1) / 100;
570         if( server->operation == HistogramEngine::HISTOGRAM ) {
571
572 #define HISTOGRAM_HEAD(type) \
573 { \
574         for( int i=pkg->start; i<pkg->end; ++i ) { \
575                 type *row = (type*)data->get_rows()[i]; \
576                 for( int j=0; j<w; ++j ) {
577
578 #define HISTOGRAM_TAIL(components) \
579                         v = MAX(r, g); v = MAX(v, b); v += slots1; \
580                         r += slots1;  g += slots1;  b += slots1; \
581                         CLAMP(r, 0, bins1);  ++accum_r[r]; \
582                         CLAMP(g, 0, bins1);  ++accum_g[g]; \
583                         CLAMP(b, 0, bins1);  ++accum_b[b]; \
584                         CLAMP(v, 0, bins1);  ++accum_v[v]; \
585                         row += components; \
586                 } \
587         } \
588 }
589
590                 VFrame *data = server->data;
591                 int w = data->get_w();
592 //              int h = data->get_h();
593                 int *accum_r = accum[HISTOGRAM_RED];
594                 int *accum_g = accum[HISTOGRAM_GREEN];
595                 int *accum_b = accum[HISTOGRAM_BLUE];
596                 int *accum_v = accum[HISTOGRAM_VALUE];
597                 int r, g, b, y, u, v;
598
599                 switch( data->get_color_model() ) {
600                 case BC_RGB888:
601                         HISTOGRAM_HEAD(unsigned char)
602                         r = row[0]; g = row[1]; b = row[2];
603                         HISTOGRAM_TAIL(3)
604                         break;
605                 case BC_RGB_FLOAT:
606                         HISTOGRAM_HEAD(float)
607                         r = (int)(row[0] * 0xffff);
608                         g = (int)(row[1] * 0xffff);
609                         b = (int)(row[2] * 0xffff);
610                         HISTOGRAM_TAIL(3)
611                         break;
612                 case BC_YUV888:
613                         HISTOGRAM_HEAD(unsigned char)
614                         y = row[0]; u = row[1]; v = row[2];
615                         YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v);
616                         HISTOGRAM_TAIL(3)
617                         break;
618                 case BC_RGBA8888:
619                         HISTOGRAM_HEAD(unsigned char)
620                         r = row[0]; g = row[1]; b = row[2];
621                         HISTOGRAM_TAIL(4)
622                         break;
623                 case BC_RGBA_FLOAT:
624                         HISTOGRAM_HEAD(float)
625                         r = (int)(row[0] * 0xffff);
626                         g = (int)(row[1] * 0xffff);
627                         b = (int)(row[2] * 0xffff);
628                         HISTOGRAM_TAIL(4)
629                         break;
630                 case BC_YUVA8888:
631                         HISTOGRAM_HEAD(unsigned char)
632                         y = row[0]; u = row[1]; v = row[2];
633                         YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v);
634                         HISTOGRAM_TAIL(4)
635                         break;
636                 case BC_RGB161616:
637                         HISTOGRAM_HEAD(uint16_t)
638                         r = row[0]; g = row[1]; b = row[2];
639                         HISTOGRAM_TAIL(3)
640                         break;
641                 case BC_YUV161616:
642                         HISTOGRAM_HEAD(uint16_t)
643                         y = row[0]; u = row[1]; v = row[2];
644                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
645                         HISTOGRAM_TAIL(3)
646                         break;
647                 case BC_RGBA16161616:
648                         HISTOGRAM_HEAD(uint16_t)
649                         r = row[0]; g = row[1]; b = row[2];
650                         HISTOGRAM_TAIL(3)
651                         break;
652                 case BC_YUVA16161616:
653                         HISTOGRAM_HEAD(uint16_t)
654                         y = row[0]; u = row[1]; v = row[2];
655                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
656                         HISTOGRAM_TAIL(4)
657                         break;
658                 }
659         }
660         else
661         if( server->operation == HistogramEngine::APPLY ) {
662
663 #define PROCESS(type, components) \
664 { \
665         for( int i=pkg->start; i<pkg->end; ++i ) { \
666                 type *row = (type*)input->get_rows()[i]; \
667                 for( int j=0; j<w; ++j ) { \
668                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
669                                 continue; \
670                         row[0] = lookup_r[row[0]]; \
671                         row[1] = lookup_g[row[1]]; \
672                         row[2] = lookup_b[row[2]]; \
673                         row += components; \
674                 } \
675         } \
676 }
677
678 #define PROCESS_YUV(type, components, max) \
679 { \
680         for( int i=pkg->start; i<pkg->end; ++i ) { \
681                 type *row = (type*)input->get_rows()[i]; \
682                 for( int j=0; j<w; ++j ) { \
683                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
684                                 continue; \
685                         y = row[0]; u = row[1]; v = row[2]; \
686                         if( max == 0xff ) \
687                                 YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \
688                         else \
689                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
690                         r = lookup_r[r]; g = lookup_g[g]; b = lookup_b[b]; \
691                         if( max == 0xff ) \
692                                 YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \
693                         else \
694                                 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
695                         row[0] = y; row[1] = u; row[2] = v; \
696                         row += components; \
697                 } \
698         } \
699 }
700
701 #define PROCESS_FLOAT(components) \
702 { \
703         for( int i=pkg->start; i<pkg->end; ++i ) { \
704                 float *row = (float*)input->get_rows()[i]; \
705                 for( int j=0; j<w; ++j ) { \
706                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
707                                 continue; \
708                         float r = row[0], g = row[1], b = row[2]; \
709                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
710                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
711                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
712                         row[0] = r; row[1] = g; row[2] = b; \
713                         row += components; \
714                 } \
715         } \
716 }
717
718
719                 VFrame *input = plugin->input;
720 //              VFrame *output = plugin->output;
721                 int w = input->get_w(), h = input->get_h();
722                 int *lookup_r = plugin->lookup[0];
723                 int *lookup_g = plugin->lookup[1];
724                 int *lookup_b = plugin->lookup[2];
725                 int r, g, b, y, u, v;
726                 switch( input->get_color_model() ) {
727                 case BC_RGB888:
728                         PROCESS(unsigned char, 3)
729                         break;
730                 case BC_RGB_FLOAT:
731                         PROCESS_FLOAT(3);
732                         break;
733                 case BC_RGBA8888:
734                         PROCESS(unsigned char, 4)
735                         break;
736                 case BC_RGBA_FLOAT:
737                         PROCESS_FLOAT(4);
738                         break;
739                 case BC_RGB161616:
740                         PROCESS(uint16_t, 3)
741                         break;
742                 case BC_RGBA16161616:
743                         PROCESS(uint16_t, 4)
744                         break;
745                 case BC_YUV888:
746                         PROCESS_YUV(unsigned char, 3, 0xff)
747                         break;
748                 case BC_YUVA8888:
749                         PROCESS_YUV(unsigned char, 4, 0xff)
750                         break;
751                 case BC_YUV161616:
752                         PROCESS_YUV(uint16_t, 3, 0xffff)
753                         break;
754                 case BC_YUVA16161616:
755                         PROCESS_YUV(uint16_t, 4, 0xffff)
756                         break;
757                 }
758         }
759 }
760
761
762 HistogramEngine::HistogramEngine(HistogramMain *plugin,
763                 int total_clients, int total_packages)
764  : LoadServer(total_clients, total_packages)
765 {
766         this->plugin = plugin;
767 }
768
769 void HistogramEngine::init_packages()
770 {
771         total_size = data->get_h();
772         for( int i=0,start=0,n=get_total_packages(); i<n; ) {
773                 HistogramPackage *package = (HistogramPackage*)get_package(i);
774                 package->start = start;
775                 package->end = start = (total_size * ++i)/ n;
776         }
777
778         int bins = plugin->slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
779 // Initialize clients here in case some don't get run.
780         for( int i=0; i<get_total_clients(); ++i ) {
781                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
782                 for( int i=0; i<HISTOGRAM_MODES; ++i )
783                         bzero(unit->accum[i], sizeof(int)*bins);
784         }
785
786 }
787
788 LoadClient* HistogramEngine::new_client()
789 {
790         return new HistogramUnit(this, plugin);
791 }
792
793 LoadPackage* HistogramEngine::new_package()
794 {
795         return new HistogramPackage;
796 }
797
798 void HistogramEngine::process_packages(int operation, VFrame *data)
799 {
800         this->data = data;
801         this->operation = operation;
802         LoadServer::process_packages();
803 }
804
805
806