histogram rework to add sum_frames, update suv/cakewalk autorange icons, add new...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / histogram / histogram.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2012 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 "bchash.h"
29 #include "bcprogressbox.h"
30 #include "bcsignals.h"
31 #include "clip.h"
32 #include "edl.h"
33 #include "filexml.h"
34 #include "histogram.h"
35 #include "histogramconfig.h"
36 #include "histogramwindow.h"
37 #include "keyframe.h"
38 #include "language.h"
39 #include "loadbalance.h"
40 #include "localsession.h"
41 #include "mainsession.h"
42 #include "mwindow.h"
43 #include "playback3d.h"
44 #include "pluginserver.h"
45 #include "bccolors.h"
46 #include "vframe.h"
47 #include "workarounds.h"
48
49 #include "aggregated.h"
50 #include "../colorbalance/aggregated.h"
51 #include "../interpolate/aggregated.h"
52 #include "../gamma/aggregated.h"
53
54 class HistogramMain;
55 class HistogramEngine;
56 class HistogramWindow;
57
58
59 REGISTER_PLUGIN(HistogramMain)
60
61 HistogramMain::HistogramMain(PluginServer *server)
62  : PluginVClient(server)
63 {
64         engine = 0;
65         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
66                 lookup[i] = new int[0x10000];
67                 preview_lookup[i] = new int[0x10000];
68                 accum[i] = new int64_t[HISTOGRAM_SLOTS];
69                 bzero(accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
70         }
71         current_point = -1;
72         mode = HISTOGRAM_VALUE;
73         last_position = -1;
74         need_reconfigure = 1;
75         sum_frames = 0;
76         frames = 1;
77         dragging_point = 0;
78         input = 0;
79         output = 0;
80         w = 440;
81         h = 500;
82         parade = 0;
83 }
84
85 HistogramMain::~HistogramMain()
86 {
87
88         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
89                 delete [] lookup[i];
90                 delete [] preview_lookup[i];
91                 delete [] accum[i];
92         }
93         delete engine;
94 }
95
96 const char* HistogramMain::plugin_title() { return N_("Histogram"); }
97 int HistogramMain::is_realtime() { return 1; }
98
99
100
101 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
102
103 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
104
105 void HistogramMain::render_gui(void *data)
106 {
107         if( !thread ) return;
108         HistogramWindow *window = (HistogramWindow*)thread->window;
109         HistogramMain *plugin = (HistogramMain*)data;
110 //update gui client instance, needed for drawing
111         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
112                 config.low_input[i] = plugin->config.low_input[i];
113                 config.high_input[i] = plugin->config.high_input[i];
114                 memcpy(accum[i], plugin->accum[i], HISTOGRAM_SLOTS*sizeof(*accum));
115         }
116         window->lock_window("HistogramMain::render_gui 2");
117 // draw all if reconfigure
118         int reconfig = plugin->need_reconfigure;
119 // Always draw the histogram but don't update widgets if automatic
120         int auto_rgb = reconfig ? 1 : config.automatic && mode != HISTOGRAM_VALUE ? 1 : 0;
121         window->update(1, auto_rgb, auto_rgb, reconfig);
122         window->unlock_window();
123 }
124
125 void HistogramMain::update_gui()
126 {
127         if( thread ) {
128                 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
129                 int reconfigure = load_configuration();
130                 if( reconfigure )
131                         ((HistogramWindow*)thread->window)->update(1, 1, 1, 1);
132                 ((HistogramWindow*)thread->window)->unlock_window();
133         }
134 }
135
136
137 void HistogramMain::save_data(KeyFrame *keyframe)
138 {
139         FileXML output;
140 // cause data to be stored directly in text
141         output.set_shared_output(keyframe->xbuf);
142         output.tag.set_title("HISTOGRAM");
143
144         char string[BCTEXTLEN];
145
146         output.tag.set_property("AUTOMATIC", config.automatic);
147         output.tag.set_property("THRESHOLD", config.threshold);
148         output.tag.set_property("PLOT", config.plot);
149         output.tag.set_property("SUM_FRAMES", config.sum_frames);
150         output.tag.set_property("SPLIT", config.split);
151         output.tag.set_property("LOG_SLIDER", config.log_slider);
152         output.tag.set_property("W", w);
153         output.tag.set_property("H", h);
154         output.tag.set_property("PARADE", parade);
155         output.tag.set_property("MODE", mode);
156
157         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
158                 sprintf(string, "LOW_OUTPUT_%d", i);
159                 output.tag.set_property(string, config.low_output[i]);
160                 sprintf(string, "HIGH_OUTPUT_%d", i);
161                 output.tag.set_property(string, config.high_output[i]);
162                 sprintf(string, "LOW_INPUT_%d", i);
163                 output.tag.set_property(string, config.low_input[i]);
164                 sprintf(string, "HIGH_INPUT_%d", i);
165                 output.tag.set_property(string, config.high_input[i]);
166                 sprintf(string, "GAMMA_%d", i);
167                 output.tag.set_property(string, config.gamma[i]);
168         }
169
170         output.append_tag();
171         output.tag.set_title("/HISTOGRAM");
172         output.append_tag();
173         output.append_newline();
174         output.terminate_string();
175 }
176
177 void HistogramMain::read_data(KeyFrame *keyframe)
178 {
179         FileXML input;
180
181         input.set_shared_input(keyframe->xbuf);
182
183         int result = 0;
184         while( !(result = input.read_tag()) ) {
185                 if( input.tag.title_is("HISTOGRAM") ) {
186                         config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
187                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
188                         config.plot = input.tag.get_property("PLOT", config.plot);
189                         config.sum_frames = input.tag.get_property("SUM_FRAMES", config.sum_frames);
190                         config.split = input.tag.get_property("SPLIT", config.split);
191                         config.log_slider = input.tag.get_property("LOG_SLIDER", config.log_slider);
192
193                         if( is_defaults() ) {
194                                 w = input.tag.get_property("W", w);
195                                 h = input.tag.get_property("H", h);
196                                 parade = input.tag.get_property("PARADE", parade);
197                                 mode = input.tag.get_property("MODE", mode);
198                         }
199
200                         char string[BCTEXTLEN];
201                         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
202                                 sprintf(string, "LOW_OUTPUT_%d", i);
203                                 config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
204                                 sprintf(string, "HIGH_OUTPUT_%d", i);
205                                 config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
206                                 sprintf(string, "GAMMA_%d", i);
207                                 config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
208
209                                 if( i == HISTOGRAM_VALUE || !config.automatic ) {
210                                         sprintf(string, "LOW_INPUT_%d", i);
211                                         config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
212                                         sprintf(string, "HIGH_INPUT_%d", i);
213                                         config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
214                                 }
215                         }
216                 }
217         }
218
219         config.boundaries();
220 }
221
222 float HistogramMain::calculate_level(float input, int mode, int use_value)
223 {
224         float output = 0.0;
225
226 // Scale to input range
227         if( !EQUIV(config.high_input[mode], config.low_input[mode]) ) {
228                 output = input < config.low_input[mode] ? 0 :
229                     (input - config.low_input[mode]) /
230                         (config.high_input[mode] - config.low_input[mode]);
231         }
232         else
233                 output = input;
234
235         if( !EQUIV(config.gamma[mode], 0) ) {
236                 output = pow(output, 1.0 / config.gamma[mode]);
237                 CLAMP(output, 0, 1.0);
238         }
239
240 // Apply value curve
241         if( use_value && mode != HISTOGRAM_VALUE )
242                 output = calculate_level(output, HISTOGRAM_VALUE, 0);
243
244 // scale to output range
245         if( !EQUIV(config.low_output[mode], config.high_output[mode]) ) {
246                 output = output * (config.high_output[mode] - config.low_output[mode]) +
247                         config.low_output[mode];
248         }
249
250         CLAMP(output, 0, 1.0);
251         return output;
252 }
253
254 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
255 {
256         if( !engine ) {
257                 int cpus = data->get_w() * data->get_h() / 0x80000 + 2;
258                 int smps = get_project_smp();
259                 if( cpus > smps ) cpus = smps;
260                 engine = new HistogramEngine(this, cpus, cpus);
261         }
262
263         engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
264
265         int k = 0;
266         HistogramUnit *unit = (HistogramUnit*)engine->get_client(0);
267         if( !sum_frames ) {
268                 frames = 0;
269                 for( int i=0; i<HISTOGRAM_MODES; ++i )
270                         memcpy(accum[i], unit->accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
271                 k = 1;
272         }
273
274         for( int i=k,n=engine->get_total_clients(); i<n; ++i ) {
275                 unit = (HistogramUnit*)engine->get_client(i);
276                 for( int j=0; j<HISTOGRAM_MODES; ++j ) {
277                         int64_t *in = unit->accum[j], *out = accum[j];
278                         for( int k=HISTOGRAM_SLOTS; --k>=0; ) *out++ += *in++;
279                 }
280         }
281
282 // Remove top and bottom from calculations.  Doesn't work in high
283 // precision colormodels.
284         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
285                 accum[i][0] = 0;
286                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
287         }
288         ++frames;
289 }
290
291
292 void HistogramMain::calculate_automatic(VFrame *data)
293 {
294         calculate_histogram(data, 0);
295         config.reset_points(1);
296
297 // Do each channel
298         for( int i=0; i<3; ++i ) {
299                 int64_t *accum = this->accum[i];
300                 int64_t sz = data->get_w() * data->get_h();
301                 int64_t pixels = sz * frames;
302                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
303                 int threshold = (int)(white_fraction * pixels);
304                 float min_level = 0.0, max_level = 1.0;
305
306 // Get histogram slot above threshold of pixels
307                 int64_t total = 0;
308                 for( int j=0; j<HISTOGRAM_SLOTS; ++j ) {
309                         total += accum[j];
310                         if( total >= threshold ) {
311                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
312                                 break;
313                         }
314                 }
315
316 // Get histogram slot below threshold of pixels
317                 total = 0;
318                 for( int j=HISTOGRAM_SLOTS; --j> 0; ) {
319                         total += accum[j];
320                         if( total >= threshold ) {
321                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
322                                 break;
323                         }
324                 }
325
326                 config.low_input[i] = min_level;
327                 config.high_input[i] = max_level;
328         }
329 }
330
331
332 int HistogramMain::calculate_use_opengl()
333 {
334 // glHistogram doesn't work.
335         int result = get_use_opengl() &&
336                 !config.automatic &&
337                 (!config.plot || !gui_open());
338         return result;
339 }
340
341
342 int HistogramMain::process_buffer(VFrame *frame,
343         int64_t start_position,
344         double frame_rate)
345 {
346         need_reconfigure = load_configuration();
347         int use_opengl = calculate_use_opengl();
348         sum_frames = last_position == start_position ? config.sum_frames : 0;
349         last_position = get_direction() == PLAY_FORWARD ?
350                         start_position+1 : start_position-1;
351         this->input = frame;
352         this->output = frame;
353         int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
354         int smps = get_project_smp();
355         if( cpus > smps ) cpus = smps;
356         if( !engine )
357                 engine = new HistogramEngine(this, cpus, cpus);
358         read_frame(frame, 0, start_position, frame_rate, use_opengl);
359         if( config.automatic )
360                 calculate_automatic(frame);
361         if( config.plot ) {
362 // Generate curves for value histogram
363                 tabulate_curve(lookup, 0);
364                 tabulate_curve(preview_lookup, 0, 0x10000);
365 // Need to get the luminance values.
366                 calculate_histogram(input, 1);
367                 send_render_gui(this);
368         }
369
370         if( need_reconfigure || config.automatic || config.plot ) {
371 // Calculate new curves
372 // Generate transfer tables with value function for integer colormodels.
373                 tabulate_curve(lookup, 1);
374         }
375
376 // Apply histogram in hardware
377         if( use_opengl )
378                 return run_opengl();
379
380 // Apply histogram
381         engine->process_packages(HistogramEngine::APPLY, input, 0);
382         return 0;
383 }
384
385 void HistogramMain::tabulate_curve(int **table, int idx, int use_value, int len)
386 {
387         int len1 = len - 1;
388         int *curve = table[idx];
389         for( int i=0; i<len; ++i ) {
390                 curve[i] = calculate_level((float)i/len1, idx, use_value) * len1;
391                 CLAMP(curve[i], 0, len1);
392         }
393 }
394
395 void HistogramMain::tabulate_curve(int **table, int use_value, int len)
396 {
397 // uint8 rgb is 8 bit, all others are converted to 16 bit RGB
398         if( len < 0 ) {
399                 int color_model = input->get_color_model();
400                 len = color_model == BC_RGB888 || color_model == BC_RGBA8888 ?
401                         0x100 : 0x10000;
402         }
403         for( int i=0; i<3; ++i )
404                 tabulate_curve(table, i, use_value, len);
405 }
406
407 int HistogramMain::handle_opengl()
408 {
409 #ifdef HAVE_GL
410 // Functions to get pixel from either previous effect or texture
411         static const char *histogram_get_pixel1 =
412                 "vec4 histogram_get_pixel()\n"
413                 "{\n"
414                 "       return gl_FragColor;\n"
415                 "}\n";
416
417         static const char *histogram_get_pixel2 =
418                 "uniform sampler2D tex;\n"
419                 "vec4 histogram_get_pixel()\n"
420                 "{\n"
421                 "       return texture2D(tex, gl_TexCoord[0].st);\n"
422                 "}\n";
423
424         static const char *head_frag =
425                 "uniform vec4 low_input;\n"
426                 "uniform vec4 high_input;\n"
427                 "uniform vec4 gamma;\n"
428                 "uniform vec4 low_output;\n"
429                 "uniform vec4 output_scale;\n"
430                 "void main()\n"
431                 "{\n"
432                 "       float temp = 0.0;\n";
433
434         static const char *get_rgb_frag =
435                 "       vec4 pixel = histogram_get_pixel();\n";
436
437         static const char *get_yuv_frag =
438                 "       vec4 pixel = histogram_get_pixel();\n"
439                         YUV_TO_RGB_FRAG("pixel");
440
441 #define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
442                 "// apply input curve\n" \
443                 "       temp = (" PIXEL " - " LOW_INPUT ") / \n" \
444                 "               (" HIGH_INPUT " - " LOW_INPUT ");\n" \
445                 "       temp = max(temp, 0.0);\n" \
446                 "       " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
447
448
449
450         static const char *apply_histogram_frag =
451                 APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
452                 APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
453                 APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
454                 "// apply output curve\n"
455                 "       pixel.rgb *= output_scale.rgb;\n"
456                 "       pixel.rgb += low_output.rgb;\n"
457                 APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
458                 APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
459                 APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
460                 "// apply output curve\n"
461                 "       pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
462                 "       pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
463
464         static const char *put_rgb_frag =
465                 "       gl_FragColor = pixel;\n"
466                 "}\n";
467
468         static const char *put_yuv_frag =
469                         RGB_TO_YUV_FRAG("pixel")
470                 "       gl_FragColor = pixel;\n"
471                 "}\n";
472
473
474
475         get_output()->to_texture();
476         get_output()->enable_opengl();
477
478         const char *shader_stack[16];
479         memset(shader_stack,0, sizeof(shader_stack));
480         int current_shader = 0;
481
482         int need_color_matrix = BC_CModels::is_yuv(get_output()->get_color_model()) ? 1 : 0;
483         if( need_color_matrix )
484                 shader_stack[current_shader++] = bc_gl_colors;
485
486         int aggregate_interpolation = 0;
487         int aggregate_gamma = 0;
488         int aggregate_colorbalance = 0;
489 // All aggregation possibilities must be accounted for because unsupported
490 // effects can get in between the aggregation members.
491         if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
492                 !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
493                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
494         {
495                 aggregate_interpolation = 1;
496                 aggregate_gamma = 1;
497                 aggregate_colorbalance = 1;
498         }
499         else
500         if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
501                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
502         {
503                 aggregate_gamma = 1;
504                 aggregate_colorbalance = 1;
505         }
506         else
507         if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
508                 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
509         {
510                 aggregate_interpolation = 1;
511                 aggregate_gamma = 1;
512         }
513         else
514         if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
515                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
516         {
517                 aggregate_interpolation = 1;
518                 aggregate_colorbalance = 1;
519         }
520         else
521         if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
522                 aggregate_interpolation = 1;
523         else
524         if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
525                 aggregate_gamma = 1;
526         else
527         if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
528                 aggregate_colorbalance = 1;
529
530 // The order of processing is fixed by this sequence
531         if(aggregate_interpolation)
532                 INTERPOLATE_COMPILE(shader_stack, current_shader);
533
534         if(aggregate_gamma)
535                 GAMMA_COMPILE(shader_stack, current_shader,
536                         aggregate_interpolation);
537
538         if(aggregate_colorbalance)
539                 COLORBALANCE_COMPILE(shader_stack, current_shader,
540                         aggregate_interpolation || aggregate_gamma);
541
542         shader_stack[current_shader++] = 
543                 aggregate_interpolation || aggregate_gamma || aggregate_colorbalance ?
544                         histogram_get_pixel1 : histogram_get_pixel2;
545
546         shader_stack[current_shader++] = head_frag;
547         shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
548                         get_yuv_frag : get_rgb_frag;
549         shader_stack[current_shader++] = apply_histogram_frag;
550         shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
551                         put_yuv_frag : put_rgb_frag;
552
553         shader_stack[current_shader] = 0;
554         unsigned int shader = VFrame::make_shader(shader_stack);
555
556 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
557 // aggregate_interpolation,
558 // aggregate_gamma,
559 // aggregate_colorbalance,
560 // current_shader,
561 // shader);
562
563         float low_input[4];
564         float high_input[4];
565         float gamma[4];
566         float low_output[4];
567         float output_scale[4];
568
569
570 // printf("min x    min y    max x    max y\n");
571 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
572 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
573 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
574 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
575
576         for(int i = 0; i < HISTOGRAM_MODES; i++)
577         {
578                 low_input[i] = config.low_input[i];
579                 high_input[i] = config.high_input[i];
580                 gamma[i] = config.gamma[i];
581                 low_output[i] = config.low_output[i];
582                 output_scale[i] = config.high_output[i] - config.low_output[i];
583         }
584
585         if(shader > 0)
586         {
587                 glUseProgram(shader);
588                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
589                 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
590                 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader);
591                 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader);
592                 glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
593                 glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
594                 glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
595                 glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
596                 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
597                 if( need_color_matrix ) BC_GL_COLORS(shader);
598         }
599
600         get_output()->init_screen();
601         get_output()->bind_texture(0);
602
603         glDisable(GL_BLEND);
604
605 // Draw the affected half
606         if(config.split)
607         {
608                 glBegin(GL_TRIANGLES);
609                 glNormal3f(0, 0, 1.0);
610
611                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
612                         0.0 / get_output()->get_texture_h());
613                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
614
615
616                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
617                         (float)get_output()->get_h() / get_output()->get_texture_h());
618                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
619
620                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
621                         (float)get_output()->get_h() / get_output()->get_texture_h());
622                 glVertex3f(0.0, -0.0, 0);
623
624
625                 glEnd();
626         }
627         else
628         {
629                 get_output()->draw_texture();
630         }
631
632         glUseProgram(0);
633
634 // Draw the unaffected half
635         if(config.split)
636         {
637                 glBegin(GL_TRIANGLES);
638                 glNormal3f(0, 0, 1.0);
639
640
641                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
642                         0.0 / get_output()->get_texture_h());
643                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
644
645                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
646                         0.0 / get_output()->get_texture_h());
647                 glVertex3f((float)get_output()->get_w(),
648                         -(float)get_output()->get_h(), 0);
649
650                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
651                         (float)get_output()->get_h() / get_output()->get_texture_h());
652                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
653
654
655                 glEnd();
656         }
657
658         get_output()->set_opengl_state(VFrame::SCREEN);
659 #endif
660         return 0;
661 }
662
663
664 HistogramPackage::HistogramPackage()
665  : LoadPackage()
666 {
667 }
668
669 HistogramUnit::HistogramUnit(HistogramEngine *server,
670         HistogramMain *plugin)
671  : LoadClient(server)
672 {
673         this->plugin = plugin;
674         this->server = server;
675         for(int i = 0; i < HISTOGRAM_MODES; i++)
676                 accum[i] = new int64_t[HISTOGRAM_SLOTS];
677 }
678
679 HistogramUnit::~HistogramUnit()
680 {
681         for(int i = 0; i < HISTOGRAM_MODES; i++)
682                 delete [] accum[i];
683 }
684
685 void HistogramUnit::process_package(LoadPackage *package)
686 {
687         HistogramPackage *pkg = (HistogramPackage*)package;
688         switch( server->operation ) {
689         case HistogramEngine::HISTOGRAM: {
690                 int do_value = server->do_value;
691                 const int hmin = HISTOGRAM_MIN * 0xffff / 100;
692                 const int slots1 = HISTOGRAM_SLOTS-1;
693
694 #define HISTOGRAM_HEAD(type) { \
695         type **rows = (type**)data->get_rows(); \
696         for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
697                 type *row = rows[iy]; \
698                 for( int ix=0; ix<w; ++ix ) {
699
700 #define HISTOGRAM_TAIL(components) \
701                         if( do_value ) { \
702                                 r_out = preview_r[bclip(r, 0, 0xffff)]; \
703                                 g_out = preview_g[bclip(g, 0, 0xffff)]; \
704                                 b_out = preview_b[bclip(b, 0, 0xffff)]; \
705 /*                              v = (r * 76 + g * 150 + b * 29) >> 8; */ \
706 /* Value takes the maximum of the output RGB values */ \
707                                 int v = MAX(r_out, g_out); v = MAX(v, b_out); \
708                                 ++accum_v[bclip(v -= hmin, 0, slots1)]; \
709                         } \
710  \
711                         ++accum_r[bclip(r -= hmin, 0, slots1)]; \
712                         ++accum_g[bclip(g -= hmin, 0, slots1)]; \
713                         ++accum_b[bclip(b -= hmin, 0, slots1)]; \
714                         row += components; \
715                 } \
716         } \
717 }
718
719                 VFrame *data = server->data;
720                 int w = data->get_w();
721                 //int h = data->get_h();
722                 int64_t *accum_r = accum[HISTOGRAM_RED];
723                 int64_t *accum_g = accum[HISTOGRAM_GREEN];
724                 int64_t *accum_b = accum[HISTOGRAM_BLUE];
725                 int64_t *accum_v = accum[HISTOGRAM_VALUE];
726                 int32_t r, g, b, y, u, v;
727                 int r_out, g_out, b_out;
728                 int *preview_r = plugin->preview_lookup[HISTOGRAM_RED];
729                 int *preview_g = plugin->preview_lookup[HISTOGRAM_GREEN];
730                 int *preview_b = plugin->preview_lookup[HISTOGRAM_BLUE];
731
732                 switch( data->get_color_model() ) {
733                 case BC_RGB888:
734                         HISTOGRAM_HEAD(unsigned char)
735                         r = (row[0] << 8) | row[0];
736                         g = (row[1] << 8) | row[1];
737                         b = (row[2] << 8) | row[2];
738                         HISTOGRAM_TAIL(3)
739                         break;
740                 case BC_RGB_FLOAT:
741                         HISTOGRAM_HEAD(float)
742                         r = (int)(row[0] * 0xffff);
743                         g = (int)(row[1] * 0xffff);
744                         b = (int)(row[2] * 0xffff);
745                         HISTOGRAM_TAIL(3)
746                         break;
747                 case BC_YUV888:
748                         HISTOGRAM_HEAD(unsigned char)
749                         y = (row[0] << 8) | row[0];
750                         u = (row[1] << 8) | row[1];
751                         v = (row[2] << 8) | row[2];
752                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
753                         HISTOGRAM_TAIL(3)
754                         break;
755                 case BC_RGBA8888:
756                         HISTOGRAM_HEAD(unsigned char)
757                         r = (row[0] << 8) | row[0];
758                         g = (row[1] << 8) | row[1];
759                         b = (row[2] << 8) | row[2];
760                         HISTOGRAM_TAIL(4)
761                         break;
762                 case BC_RGBA_FLOAT:
763                         HISTOGRAM_HEAD(float)
764                         r = (int)(row[0] * 0xffff);
765                         g = (int)(row[1] * 0xffff);
766                         b = (int)(row[2] * 0xffff);
767                         HISTOGRAM_TAIL(4)
768                         break;
769                 case BC_YUVA8888:
770                         HISTOGRAM_HEAD(unsigned char)
771                         y = (row[0] << 8) | row[0];
772                         u = (row[1] << 8) | row[1];
773                         v = (row[2] << 8) | row[2];
774                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
775                         HISTOGRAM_TAIL(4)
776                         break;
777                 case BC_RGB161616:
778                         HISTOGRAM_HEAD(uint16_t)
779                         r = row[0];
780                         g = row[1];
781                         b = row[2];
782                         HISTOGRAM_TAIL(3)
783                         break;
784                 case BC_YUV161616:
785                         HISTOGRAM_HEAD(uint16_t)
786                         y = row[0];
787                         u = row[1];
788                         v = row[2];
789                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
790                         HISTOGRAM_TAIL(3)
791                         break;
792                 case BC_RGBA16161616:
793                         HISTOGRAM_HEAD(uint16_t)
794                         r = row[0];
795                         g = row[1];
796                         b = row[2];
797                         HISTOGRAM_TAIL(3)
798                         break;
799                 case BC_YUVA16161616:
800                         HISTOGRAM_HEAD(uint16_t)
801                         y = row[0];
802                         u = row[1];
803                         v = row[2];
804                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
805                         HISTOGRAM_TAIL(4)
806                         break;
807                 }
808                 break; }
809         case HistogramEngine::APPLY: {
810
811 #define PROCESS(type, components) { \
812         type **rows = (type**)input->get_rows(); \
813         for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
814                 type *row = rows[iy]; \
815                 for( int ix=0; ix<w; ++ix ) { \
816                         if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
817                                 continue; \
818                         row[0] = lookup_r[row[0]]; \
819                         row[1] = lookup_g[row[1]]; \
820                         row[2] = lookup_b[row[2]]; \
821                         row += components; \
822                 } \
823         } \
824 }
825
826 #define PROCESS_YUV(type, components, max) { \
827         type **rows = (type**)input->get_rows(); \
828         for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
829                 type *row = rows[iy]; \
830                 for( int ix=0; ix<w; ++ix ) { \
831                         if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
832                                 continue; \
833                         if( max == 0xff ) { /* Convert to 16 bit RGB */ \
834                                 y = (row[0] << 8) | row[0]; \
835                                 u = (row[1] << 8) | row[1]; \
836                                 v = (row[2] << 8) | row[2]; \
837                         } \
838                         else { \
839                                 y = row[0]; \
840                                 u = row[1]; \
841                                 v = row[2]; \
842                         } \
843                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
844 /* Look up in RGB domain */ \
845                         r = lookup_r[r]; \
846                         g = lookup_g[g]; \
847                         b = lookup_b[b]; \
848 /* Convert to 16 bit YUV */ \
849                         YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
850                         if( max == 0xff ) { \
851                                 row[0] = y >> 8; \
852                                 row[1] = u >> 8; \
853                                 row[2] = v >> 8; \
854                         } \
855                         else { \
856                                 row[0] = y; \
857                                 row[1] = u; \
858                                 row[2] = v; \
859                         } \
860                         row += components; \
861                 } \
862         } \
863 }
864
865 #define PROCESS_FLOAT(components) { \
866         float **rows = (float**)input->get_rows(); \
867         for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
868                 float *row = rows[iy]; \
869                 for( int ix=0; ix<w; ++ix ) { \
870                         if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
871                                 continue; \
872                         float fr = row[0]; \
873                         float fg = row[1]; \
874                         float fb = row[2]; \
875                         row[0]  = plugin->calculate_level(fr, HISTOGRAM_RED, 1); \
876                         row[1]  = plugin->calculate_level(fg, HISTOGRAM_GREEN, 1); \
877                         row[2]  = plugin->calculate_level(fb, HISTOGRAM_BLUE, 1); \
878                         row += components; \
879                 } \
880         } \
881 }
882
883                 VFrame *input = plugin->input;
884                 //VFrame *output = plugin->output;
885                 int w = input->get_w();
886                 int h = input->get_h();
887                 int *lookup_r = plugin->lookup[0];
888                 int *lookup_g = plugin->lookup[1];
889                 int *lookup_b = plugin->lookup[2];
890                 int r, g, b, y, u, v;
891                 switch( input->get_color_model() ) {
892                 case BC_RGB888:
893                         PROCESS(unsigned char, 3)
894                         break;
895                 case BC_RGB_FLOAT:
896                         PROCESS_FLOAT(3);
897                         break;
898                 case BC_RGBA8888:
899                         PROCESS(unsigned char, 4)
900                         break;
901                 case BC_RGBA_FLOAT:
902                         PROCESS_FLOAT(4);
903                         break;
904                 case BC_RGB161616:
905                         PROCESS(uint16_t, 3)
906                         break;
907                 case BC_RGBA16161616:
908                         PROCESS(uint16_t, 4)
909                         break;
910                 case BC_YUV888:
911                         PROCESS_YUV(unsigned char, 3, 0xff)
912                         break;
913                 case BC_YUVA8888:
914                         PROCESS_YUV(unsigned char, 4, 0xff)
915                         break;
916                 case BC_YUV161616:
917                         PROCESS_YUV(uint16_t, 3, 0xffff)
918                         break;
919                 case BC_YUVA16161616:
920                         PROCESS_YUV(uint16_t, 4, 0xffff)
921                         break;
922                 }
923                 break; }
924         }
925 }
926
927
928 HistogramEngine::HistogramEngine(HistogramMain *plugin,
929         int total_clients, int total_packages)
930  : LoadServer(total_clients, total_packages)
931 {
932         this->plugin = plugin;
933 }
934
935 void HistogramEngine::init_packages()
936 {
937         switch(operation) {
938         case HISTOGRAM:
939                 total_size = data->get_h();
940                 break;
941         case APPLY:
942                 total_size = data->get_h();
943                 break;
944         }
945
946         int start = 0;
947         for( int i=0,n=get_total_packages(); i<n; ++i ) {
948                 HistogramPackage *package = (HistogramPackage*)get_package(i);
949                 package->start = start;
950                 package->end = total_size * (i+1)/n;
951                 start = package->end;
952         }
953
954 // Initialize clients here in case some don't get run.
955         for( int i=0,n=get_total_clients(); i<n; ++i ) {
956                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
957                 for( int j=0; j<HISTOGRAM_MODES; ++j )
958                         bzero(unit->accum[j], sizeof(int64_t) * HISTOGRAM_SLOTS);
959         }
960 }
961
962 LoadClient* HistogramEngine::new_client()
963 {
964         return new HistogramUnit(this, plugin);
965 }
966
967 LoadPackage* HistogramEngine::new_package()
968 {
969         return new HistogramPackage;
970 }
971
972 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
973 {
974         this->data = data;
975         this->operation = operation;
976         this->do_value = do_value;
977         LoadServer::process_packages();
978 }
979
980