6 #include "bcdisplayinfo.h"
11 #include "histogram.h"
12 #include "histogramconfig.h"
13 #include "histogramwindow.h"
16 #include "loadbalance.h"
17 #include "playback3d.h"
18 #include "plugincolors.h"
20 #include "workarounds.h"
22 #include "aggregated.h"
23 #include "../colorbalance/aggregated.h"
24 #include "../interpolate/aggregated.h"
25 #include "../gamma/aggregated.h"
28 class HistogramEngine;
29 class HistogramWindow;
35 REGISTER_PLUGIN(HistogramMain)
48 HistogramMain::HistogramMain(PluginServer *server)
49 : PluginVClient(server)
51 PLUGIN_CONSTRUCTOR_MACRO
53 for(int i = 0; i < HISTOGRAM_MODES; i++)
59 preview_lookup[i] = 0;
62 mode = HISTOGRAM_VALUE;
68 HistogramMain::~HistogramMain()
70 PLUGIN_DESTRUCTOR_MACRO
71 for(int i = 0; i < HISTOGRAM_MODES;i++)
74 delete [] smoothed[i];
77 delete [] preview_lookup[i];
82 char* HistogramMain::plugin_title() { return N_("Histogram"); }
83 int HistogramMain::is_realtime() { return 1; }
86 #include "picon_png.h"
87 NEW_PICON_MACRO(HistogramMain)
89 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
91 SET_STRING_MACRO(HistogramMain)
93 RAISE_WINDOW_MACRO(HistogramMain)
95 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
97 void HistogramMain::render_gui(void *data)
102 // Process just the RGB values to determine the automatic points or
103 // all the points if manual
104 if(!config.automatic)
106 // Generate curves for value histogram
107 // Lock out changes to curves
108 thread->window->lock_window("HistogramMain::render_gui 1");
109 tabulate_curve(HISTOGRAM_RED, 0);
110 tabulate_curve(HISTOGRAM_GREEN, 0);
111 tabulate_curve(HISTOGRAM_BLUE, 0);
112 thread->window->unlock_window();
115 calculate_histogram((VFrame*)data, !config.automatic);
122 calculate_automatic((VFrame*)data);
125 // Generate curves for value histogram
126 // Lock out changes to curves
127 thread->window->lock_window("HistogramMain::render_gui 1");
128 tabulate_curve(HISTOGRAM_RED, 0);
129 tabulate_curve(HISTOGRAM_GREEN, 0);
130 tabulate_curve(HISTOGRAM_BLUE, 0);
131 thread->window->unlock_window();
134 // Need a second pass to get the luminance values.
135 calculate_histogram((VFrame*)data, 1);
140 thread->window->lock_window("HistogramMain::render_gui 2");
141 thread->window->update_canvas();
144 thread->window->update_input();
146 thread->window->unlock_window();
151 void HistogramMain::update_gui()
155 thread->window->lock_window("HistogramMain::update_gui");
156 int reconfigure = load_configuration();
159 thread->window->update(0);
160 if(!config.automatic)
162 thread->window->update_input();
165 thread->window->unlock_window();
170 int HistogramMain::load_defaults()
172 char directory[BCTEXTLEN], string[BCTEXTLEN];
173 // set the default directory
174 sprintf(directory, "%shistogram.rc", BCASTDIR);
177 defaults = new BC_Hash(directory);
180 for(int j = 0; j < HISTOGRAM_MODES; j++)
182 while(config.points[j].last) delete config.points[j].last;
184 sprintf(string, "TOTAL_POINTS_%d", j);
185 int total_points = defaults->get(string, 0);
187 for(int i = 0; i < total_points; i++)
189 HistogramPoint *point = new HistogramPoint;
190 sprintf(string, "INPUT_X_%d_%d", j, i);
191 point->x = defaults->get(string, point->x);
192 sprintf(string, "INPUT_Y_%d_%d", j, i);
193 point->y = defaults->get(string, point->y);
194 config.points[j].append(point);
199 for(int i = 0; i < HISTOGRAM_MODES; i++)
201 sprintf(string, "OUTPUT_MIN_%d", i);
202 config.output_min[i] = defaults->get(string, config.output_min[i]);
203 sprintf(string, "OUTPUT_MAX_%d", i);
204 config.output_max[i] = defaults->get(string, config.output_max[i]);
207 config.automatic = defaults->get("AUTOMATIC", config.automatic);
208 mode = defaults->get("MODE", mode);
209 CLAMP(mode, 0, HISTOGRAM_MODES - 1);
210 config.threshold = defaults->get("THRESHOLD", config.threshold);
211 config.plot = defaults->get("PLOT", config.plot);
212 config.split = defaults->get("SPLIT", config.split);
218 int HistogramMain::save_defaults()
220 char string[BCTEXTLEN];
224 for(int j = 0; j < HISTOGRAM_MODES; j++)
226 int total_points = config.points[j].total();
227 sprintf(string, "TOTAL_POINTS_%d", j);
228 defaults->update(string, total_points);
229 HistogramPoint *current = config.points[j].first;
233 sprintf(string, "INPUT_X_%d_%d", j, number);
234 defaults->update(string, current->x);
235 sprintf(string, "INPUT_Y_%d_%d", j, number);
236 defaults->update(string, current->y);
243 for(int i = 0; i < HISTOGRAM_MODES; i++)
245 sprintf(string, "OUTPUT_MIN_%d", i);
246 defaults->update(string, config.output_min[i]);
247 sprintf(string, "OUTPUT_MAX_%d", i);
248 defaults->update(string, config.output_max[i]);
251 defaults->update("AUTOMATIC", config.automatic);
252 defaults->update("MODE", mode);
253 defaults->update("THRESHOLD", config.threshold);
254 defaults->update("PLOT", config.plot);
255 defaults->update("SPLIT", config.split);
262 void HistogramMain::save_data(KeyFrame *keyframe)
266 // cause data to be stored directly in text
267 output.set_shared_string(keyframe->data, MESSAGESIZE);
268 output.tag.set_title("HISTOGRAM");
270 char string[BCTEXTLEN];
273 for(int i = 0; i < HISTOGRAM_MODES; i++)
275 sprintf(string, "OUTPUT_MIN_%d", i);
276 output.tag.set_property(string, config.output_min[i]);
277 sprintf(string, "OUTPUT_MAX_%d", i);
278 output.tag.set_property(string, config.output_max[i]);
279 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
282 output.tag.set_property("AUTOMATIC", config.automatic);
283 output.tag.set_property("THRESHOLD", config.threshold);
284 output.tag.set_property("PLOT", config.plot);
285 output.tag.set_property("SPLIT", config.split);
287 output.append_newline();
293 for(int j = 0; j < HISTOGRAM_MODES; j++)
295 output.tag.set_title("POINTS");
297 output.append_newline();
300 HistogramPoint *current = config.points[j].first;
303 output.tag.set_title("POINT");
304 output.tag.set_property("X", current->x);
305 output.tag.set_property("Y", current->y);
307 output.append_newline();
312 output.tag.set_title("/POINTS");
314 output.append_newline();
322 output.terminate_string();
325 void HistogramMain::read_data(KeyFrame *keyframe)
329 input.set_shared_string(keyframe->data, strlen(keyframe->data));
332 int current_input_mode = 0;
337 result = input.read_tag();
341 if(input.tag.title_is("HISTOGRAM"))
343 char string[BCTEXTLEN];
344 for(int i = 0; i < HISTOGRAM_MODES; i++)
346 sprintf(string, "OUTPUT_MIN_%d", i);
347 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
348 sprintf(string, "OUTPUT_MAX_%d", i);
349 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
350 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
352 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
353 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
354 config.plot = input.tag.get_property("PLOT", config.plot);
355 config.split = input.tag.get_property("SPLIT", config.split);
358 if(input.tag.title_is("POINTS"))
360 if(current_input_mode < HISTOGRAM_MODES)
362 HistogramPoints *points = &config.points[current_input_mode];
367 result = input.read_tag();
370 if(input.tag.title_is("/POINTS"))
375 if(input.tag.title_is("POINT"))
378 input.tag.get_property("X", 0.0),
379 input.tag.get_property("Y", 0.0));
385 current_input_mode++;
394 float HistogramMain::calculate_linear(float input,
423 // Get 2 points surrounding current position
424 HistogramPoints *points = &config.points[subscript];
425 HistogramPoint *current = points->first;
427 while(current && !done)
429 if(current->x > input)
439 current = points->last;
441 while(current && !done)
443 if(current->x <= input)
457 if(!EQUIV(x2 - x1, 0))
458 output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
471 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
475 float output_min = config.output_min[subscript];
476 float output_max = config.output_max[subscript];
481 // Compress output for value followed by channel
482 output = output_min +
484 (output_max - output_min);
490 float HistogramMain::calculate_smooth(float input, int subscript)
492 float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
495 CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
496 CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
497 CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
499 float smooth1 = smoothed[subscript][x_i1];
500 float smooth2 = smoothed[subscript][x_i2];
501 float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
502 CLAMP(result, 0, 1.0);
507 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
510 if(!engine) engine = new HistogramEngine(this,
511 get_project_smp() + 1,
512 get_project_smp() + 1);
516 for(int i = 0; i < HISTOGRAM_MODES; i++)
517 accum[i] = new int[HISTOGRAM_SLOTS];
520 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
522 for(int i = 0; i < engine->get_total_clients(); i++)
524 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
528 for(int j = 0; j < HISTOGRAM_MODES; j++)
530 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
535 for(int j = 0; j < HISTOGRAM_MODES; j++)
538 int *in = unit->accum[j];
539 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
545 // Remove top and bottom from calculations. Doesn't work in high
546 // precision colormodels.
547 for(int i = 0; i < HISTOGRAM_MODES; i++)
550 accum[i][HISTOGRAM_SLOTS - 1] = 0;
555 void HistogramMain::calculate_automatic(VFrame *data)
557 calculate_histogram(data, 0);
558 config.reset_points(1);
561 for(int i = 0; i < 3; i++)
563 int *accum = this->accum[i];
564 int pixels = data->get_w() * data->get_h();
565 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
566 int threshold = (int)(white_fraction * pixels);
568 float max_level = 1.0;
569 float min_level = 0.0;
571 // Get histogram slot above threshold of pixels
572 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
575 if(total >= threshold)
577 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
582 // Get slot below 99% of pixels
584 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
587 if(total >= threshold)
589 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
595 config.points[i].insert(max_level, 1.0);
596 config.points[i].insert(min_level, 0.0);
604 int HistogramMain::calculate_use_opengl()
606 // glHistogram doesn't work.
607 int result = get_use_opengl() &&
609 config.points[HISTOGRAM_RED].total() < 3 &&
610 config.points[HISTOGRAM_GREEN].total() < 3 &&
611 config.points[HISTOGRAM_BLUE].total() < 3 &&
612 config.points[HISTOGRAM_VALUE].total() < 3 &&
613 (!config.plot || !gui_open());
618 int HistogramMain::process_buffer(VFrame *frame,
619 int64_t start_position,
623 int need_reconfigure = load_configuration();
627 int use_opengl = calculate_use_opengl();
629 //printf("%d\n", use_opengl);
636 // Apply histogram in hardware
637 if(use_opengl) return run_opengl();
639 if(!engine) engine = new HistogramEngine(this,
640 get_project_smp() + 1,
641 get_project_smp() + 1);
643 this->output = frame;
645 // Always plot to set the curves if automatic
646 if(config.plot || config.automatic) send_render_gui(frame);
649 // Generate tables here. The same table is used by many packages to render
650 // each horizontal stripe. Need to cover the entire output range in each
651 // table to avoid green borders
652 if(need_reconfigure ||
659 // Calculate new curves
662 calculate_automatic(input);
666 // Generate transfer tables with value function for integer colormodels.
667 for(int i = 0; i < 3; i++)
668 tabulate_curve(i, 1);
675 engine->process_packages(HistogramEngine::APPLY, input, 0);
682 void HistogramMain::tabulate_curve(int subscript, int use_value)
685 if(!lookup[subscript])
686 lookup[subscript] = new int[HISTOGRAM_SLOTS];
687 if(!smoothed[subscript])
688 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
689 if(!linear[subscript])
690 linear[subscript] = new float[HISTOGRAM_SLOTS];
691 if(!preview_lookup[subscript])
692 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
695 float *current_smooth = smoothed[subscript];
696 float *current_linear = linear[subscript];
699 for(i = 0; i < HISTOGRAM_SLOTS; i++)
701 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
702 current_linear[i] = calculate_linear(input, subscript, use_value);
710 // Make smooth curve (currently a copy of the linear curve)
712 for(i = 0; i < HISTOGRAM_SLOTS; i++)
714 // current_smooth[i] = current_linear[i] * 0.001 +
716 // prev = current_smooth[i];
718 current_smooth[i] = current_linear[i];
721 // Generate lookup tables for integer colormodels
724 switch(input->get_color_model())
728 for(i = 0; i < 0x100; i++)
729 lookup[subscript][i] =
730 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
732 // All other integer colormodels are converted to 16 bit RGB
734 for(i = 0; i < 0x10000; i++)
735 lookup[subscript][i] =
736 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
741 // Lookup table for preview only used for GUI
744 for(i = 0; i < 0x10000; i++)
745 preview_lookup[subscript][i] =
746 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
750 int HistogramMain::handle_opengl()
753 // Functions to get pixel from either previous effect or texture
754 static char *histogram_get_pixel1 =
755 "vec4 histogram_get_pixel()\n"
757 " return gl_FragColor;\n"
760 static char *histogram_get_pixel2 =
761 "uniform sampler2D tex;\n"
762 "vec4 histogram_get_pixel()\n"
764 " return texture2D(tex, gl_TexCoord[0].st);\n"
767 static char *head_frag =
768 "// first input point\n"
769 "uniform vec2 input_min_r;\n"
770 "uniform vec2 input_min_g;\n"
771 "uniform vec2 input_min_b;\n"
772 "uniform vec2 input_min_v;\n"
773 "// second input point\n"
774 "uniform vec2 input_max_r;\n"
775 "uniform vec2 input_max_g;\n"
776 "uniform vec2 input_max_b;\n"
777 "uniform vec2 input_max_v;\n"
779 "uniform vec4 output_min;\n"
780 "uniform vec4 output_scale;\n"
784 static char *get_rgb_frag =
785 " vec4 pixel = histogram_get_pixel();\n";
787 static char *get_yuv_frag =
788 " vec4 pixel = histogram_get_pixel();\n"
789 YUV_TO_RGB_FRAG("pixel");
791 #define APPLY_INPUT_CURVE(PIXEL, INPUT_MIN, INPUT_MAX) \
792 "// apply input curve\n" \
793 " if(" PIXEL " < 0.0)\n" \
794 " " PIXEL " = 0.0;\n" \
796 " if(" PIXEL " < " INPUT_MIN ".x)\n" \
797 " " PIXEL " = " PIXEL " * " INPUT_MIN ".y / " INPUT_MIN ".x;\n" \
799 " if(" PIXEL " < " INPUT_MAX ".x)\n" \
800 " " PIXEL " = (" PIXEL " - " INPUT_MIN ".x) * \n" \
801 " (" INPUT_MAX ".y - " INPUT_MIN ".y) / \n" \
802 " (" INPUT_MAX ".x - " INPUT_MIN ".x) + \n" \
803 " " INPUT_MIN ".y;\n" \
805 " if(" PIXEL " < 1.0)\n" \
806 " " PIXEL " = (" PIXEL " - " INPUT_MAX ".x) * \n" \
807 " (1.0 - " INPUT_MAX ".y) / \n" \
808 " (1.0 - " INPUT_MAX ".x) + \n" \
809 " " INPUT_MAX ".y;\n" \
811 " " PIXEL " = 1.0;\n"
815 static char *apply_histogram_frag =
816 APPLY_INPUT_CURVE("pixel.r", "input_min_r", "input_max_r")
817 APPLY_INPUT_CURVE("pixel.g", "input_min_g", "input_max_g")
818 APPLY_INPUT_CURVE("pixel.b", "input_min_b", "input_max_b")
819 "// apply output curve\n"
820 " pixel.rgb *= output_scale.rgb;\n"
821 " pixel.rgb += output_min.rgb;\n"
822 APPLY_INPUT_CURVE("pixel.r", "input_min_v", "input_max_v")
823 APPLY_INPUT_CURVE("pixel.g", "input_min_v", "input_max_v")
824 APPLY_INPUT_CURVE("pixel.b", "input_min_v", "input_max_v")
825 "// apply output curve\n"
826 " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
827 " pixel.rgb += vec3(output_min.a, output_min.a, output_min.a);\n";
829 static char *put_rgb_frag =
830 " gl_FragColor = pixel;\n"
833 static char *put_yuv_frag =
834 RGB_TO_YUV_FRAG("pixel")
835 " gl_FragColor = pixel;\n"
840 get_output()->to_texture();
841 get_output()->enable_opengl();
843 char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
844 int current_shader = 0;
845 int aggregate_interpolation = 0;
846 int aggregate_gamma = 0;
847 int aggregate_colorbalance = 0;
848 // All aggregation possibilities must be accounted for because unsupported
849 // effects can get in between the aggregation members.
850 if(!strcmp(get_output()->get_prev_effect(2), "Interpolate Pixels") &&
851 !strcmp(get_output()->get_prev_effect(1), "Gamma") &&
852 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
854 aggregate_interpolation = 1;
856 aggregate_colorbalance = 1;
859 if(!strcmp(get_output()->get_prev_effect(1), "Gamma") &&
860 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
863 aggregate_colorbalance = 1;
866 if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
867 !strcmp(get_output()->get_prev_effect(0), "Gamma"))
869 aggregate_interpolation = 1;
873 if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
874 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
876 aggregate_interpolation = 1;
877 aggregate_colorbalance = 1;
880 if(!strcmp(get_output()->get_prev_effect(0), "Interpolate Pixels"))
881 aggregate_interpolation = 1;
883 if(!strcmp(get_output()->get_prev_effect(0), "Gamma"))
886 if(!strcmp(get_output()->get_prev_effect(0), "Color Balance"))
887 aggregate_colorbalance = 1;
890 // The order of processing is fixed by this sequence
891 if(aggregate_interpolation)
892 INTERPOLATE_COMPILE(shader_stack,
896 GAMMA_COMPILE(shader_stack,
898 aggregate_interpolation)
900 if(aggregate_colorbalance)
901 COLORBALANCE_COMPILE(shader_stack,
903 aggregate_interpolation || aggregate_gamma)
906 if(aggregate_interpolation || aggregate_gamma || aggregate_colorbalance)
907 shader_stack[current_shader++] = histogram_get_pixel1;
909 shader_stack[current_shader++] = histogram_get_pixel2;
911 unsigned int shader = 0;
912 switch(get_output()->get_color_model())
916 shader_stack[current_shader++] = head_frag;
917 shader_stack[current_shader++] = get_yuv_frag;
918 shader_stack[current_shader++] = apply_histogram_frag;
919 shader_stack[current_shader++] = put_yuv_frag;
922 shader_stack[current_shader++] = head_frag;
923 shader_stack[current_shader++] = get_rgb_frag;
924 shader_stack[current_shader++] = apply_histogram_frag;
925 shader_stack[current_shader++] = put_rgb_frag;
929 shader = VFrame::make_shader(0,
948 printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
949 aggregate_interpolation,
951 aggregate_colorbalance,
955 float input_min_r[2] = { 0, 0 };
956 float input_min_g[2] = { 0, 0 };
957 float input_min_b[2] = { 0, 0 };
958 float input_min_v[2] = { 0, 0 };
959 float input_max_r[2] = { 1, 1 };
960 float input_max_g[2] = { 1, 1 };
961 float input_max_b[2] = { 1, 1 };
962 float input_max_v[2] = { 1, 1 };
963 float output_min[4] = { 0, 0, 0, 0 };
964 float output_scale[4] = { 1, 1, 1, 1 };
967 HistogramPoint *point1, *point2;
969 #define CONVERT_POINT(index, input_min, input_max) \
970 point1 = config.points[index].first; \
971 point2 = config.points[index].last; \
974 input_min[0] = point1->x; \
975 input_min[1] = point1->y; \
976 if(point2 != point1) \
978 input_max[0] = point2->x; \
979 input_max[1] = point2->y; \
983 CONVERT_POINT(HISTOGRAM_RED, input_min_r, input_max_r);
984 CONVERT_POINT(HISTOGRAM_GREEN, input_min_g, input_max_g);
985 CONVERT_POINT(HISTOGRAM_BLUE, input_min_b, input_max_b);
986 CONVERT_POINT(HISTOGRAM_VALUE, input_min_v, input_max_v);
988 // printf("min x min y max x max y\n");
989 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
990 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
991 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
992 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
994 for(int i = 0; i < HISTOGRAM_MODES; i++)
996 output_min[i] = config.output_min[i];
997 output_scale[i] = config.output_max[i] - config.output_min[i];
1002 glUseProgram(shader);
1003 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1004 if(aggregate_gamma) GAMMA_UNIFORMS(shader)
1005 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader)
1006 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader)
1007 glUniform2fv(glGetUniformLocation(shader, "input_min_r"), 1, input_min_r);
1008 glUniform2fv(glGetUniformLocation(shader, "input_min_g"), 1, input_min_g);
1009 glUniform2fv(glGetUniformLocation(shader, "input_min_b"), 1, input_min_b);
1010 glUniform2fv(glGetUniformLocation(shader, "input_min_v"), 1, input_min_v);
1011 glUniform2fv(glGetUniformLocation(shader, "input_max_r"), 1, input_max_r);
1012 glUniform2fv(glGetUniformLocation(shader, "input_max_g"), 1, input_max_g);
1013 glUniform2fv(glGetUniformLocation(shader, "input_max_b"), 1, input_max_b);
1014 glUniform2fv(glGetUniformLocation(shader, "input_max_v"), 1, input_max_v);
1015 glUniform4fv(glGetUniformLocation(shader, "output_min"), 1, output_min);
1016 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
1019 get_output()->init_screen();
1020 get_output()->bind_texture(0);
1022 glDisable(GL_BLEND);
1024 // Draw the affected half
1027 glBegin(GL_TRIANGLES);
1028 glNormal3f(0, 0, 1.0);
1030 glTexCoord2f(0.0 / get_output()->get_texture_w(),
1031 0.0 / get_output()->get_texture_h());
1032 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
1035 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
1036 (float)get_output()->get_h() / get_output()->get_texture_h());
1037 glVertex3f((float)get_output()->get_w(), -0.0, 0);
1039 glTexCoord2f(0.0 / get_output()->get_texture_w(),
1040 (float)get_output()->get_h() / get_output()->get_texture_h());
1041 glVertex3f(0.0, -0.0, 0);
1048 get_output()->draw_texture();
1053 // Draw the unaffected half
1056 glBegin(GL_TRIANGLES);
1057 glNormal3f(0, 0, 1.0);
1060 glTexCoord2f(0.0 / get_output()->get_texture_w(),
1061 0.0 / get_output()->get_texture_h());
1062 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
1064 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
1065 0.0 / get_output()->get_texture_h());
1066 glVertex3f((float)get_output()->get_w(),
1067 -(float)get_output()->get_h(), 0);
1069 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
1070 (float)get_output()->get_h() / get_output()->get_texture_h());
1071 glVertex3f((float)get_output()->get_w(), -0.0, 0);
1077 get_output()->set_opengl_state(VFrame::SCREEN);
1092 HistogramPackage::HistogramPackage()
1100 HistogramUnit::HistogramUnit(HistogramEngine *server,
1101 HistogramMain *plugin)
1102 : LoadClient(server)
1104 this->plugin = plugin;
1105 this->server = server;
1106 for(int i = 0; i < HISTOGRAM_MODES; i++)
1107 accum[i] = new int[HISTOGRAM_SLOTS];
1110 HistogramUnit::~HistogramUnit()
1112 for(int i = 0; i < HISTOGRAM_MODES; i++)
1116 void HistogramUnit::process_package(LoadPackage *package)
1118 HistogramPackage *pkg = (HistogramPackage*)package;
1120 if(server->operation == HistogramEngine::HISTOGRAM)
1122 int do_value = server->do_value;
1125 #define HISTOGRAM_HEAD(type) \
1127 for(int i = pkg->start; i < pkg->end; i++) \
1129 type *row = (type*)data->get_rows()[i]; \
1130 for(int j = 0; j < w; j++) \
1133 #define HISTOGRAM_TAIL(components) \
1134 /* Value takes the maximum of the output RGB values */ \
1137 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
1138 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
1139 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
1140 r_out = lookup_r[r]; \
1141 g_out = lookup_g[g]; \
1142 b_out = lookup_b[b]; \
1143 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
1144 v = MAX(r_out, g_out); \
1145 v = MAX(v, b_out); \
1146 v += -HISTOGRAM_MIN * 0xffff / 100; \
1147 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
1151 r += -HISTOGRAM_MIN * 0xffff / 100; \
1152 g += -HISTOGRAM_MIN * 0xffff / 100; \
1153 b += -HISTOGRAM_MIN * 0xffff / 100; \
1154 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
1155 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
1156 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
1160 row += components; \
1168 VFrame *data = server->data;
1169 int w = data->get_w();
1170 int h = data->get_h();
1171 int *accum_r = accum[HISTOGRAM_RED];
1172 int *accum_g = accum[HISTOGRAM_GREEN];
1173 int *accum_b = accum[HISTOGRAM_BLUE];
1174 int *accum_v = accum[HISTOGRAM_VALUE];
1175 int32_t r, g, b, a, y, u, v;
1176 int r_out, g_out, b_out;
1177 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
1178 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
1179 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
1181 switch(data->get_color_model())
1184 HISTOGRAM_HEAD(unsigned char)
1185 r = (row[0] << 8) | row[0];
1186 g = (row[1] << 8) | row[1];
1187 b = (row[2] << 8) | row[2];
1191 HISTOGRAM_HEAD(float)
1192 r = (int)(row[0] * 0xffff);
1193 g = (int)(row[1] * 0xffff);
1194 b = (int)(row[2] * 0xffff);
1198 HISTOGRAM_HEAD(unsigned char)
1199 y = (row[0] << 8) | row[0];
1200 u = (row[1] << 8) | row[1];
1201 v = (row[2] << 8) | row[2];
1202 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1206 HISTOGRAM_HEAD(unsigned char)
1207 r = (row[0] << 8) | row[0];
1208 g = (row[1] << 8) | row[1];
1209 b = (row[2] << 8) | row[2];
1213 HISTOGRAM_HEAD(float)
1214 r = (int)(row[0] * 0xffff);
1215 g = (int)(row[1] * 0xffff);
1216 b = (int)(row[2] * 0xffff);
1220 HISTOGRAM_HEAD(unsigned char)
1221 y = (row[0] << 8) | row[0];
1222 u = (row[1] << 8) | row[1];
1223 v = (row[2] << 8) | row[2];
1224 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1228 HISTOGRAM_HEAD(uint16_t)
1235 HISTOGRAM_HEAD(uint16_t)
1239 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1242 case BC_RGBA16161616:
1243 HISTOGRAM_HEAD(uint16_t)
1249 case BC_YUVA16161616:
1250 HISTOGRAM_HEAD(uint16_t)
1254 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1260 if(server->operation == HistogramEngine::APPLY)
1265 #define PROCESS(type, components) \
1267 for(int i = pkg->start; i < pkg->end; i++) \
1269 type *row = (type*)input->get_rows()[i]; \
1270 for(int j = 0; j < w; j++) \
1272 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1274 row[0] = lookup_r[row[0]]; \
1275 row[1] = lookup_g[row[1]]; \
1276 row[2] = lookup_b[row[2]]; \
1277 row += components; \
1282 #define PROCESS_YUV(type, components, max) \
1284 for(int i = pkg->start; i < pkg->end; i++) \
1286 type *row = (type*)input->get_rows()[i]; \
1287 for(int j = 0; j < w; j++) \
1289 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1291 /* Convert to 16 bit RGB */ \
1294 y = (row[0] << 8) | row[0]; \
1295 u = (row[1] << 8) | row[1]; \
1296 v = (row[2] << 8) | row[2]; \
1305 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1307 /* Look up in RGB domain */ \
1312 /* Convert to 16 bit YUV */ \
1313 plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1327 row += components; \
1332 #define PROCESS_FLOAT(components) \
1334 for(int i = pkg->start; i < pkg->end; i++) \
1336 float *row = (float*)input->get_rows()[i]; \
1337 for(int j = 0; j < w; j++) \
1339 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1345 r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
1346 g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
1347 b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
1353 row += components; \
1359 VFrame *input = plugin->input;
1360 VFrame *output = plugin->output;
1361 int w = input->get_w();
1362 int h = input->get_h();
1363 int *lookup_r = plugin->lookup[0];
1364 int *lookup_g = plugin->lookup[1];
1365 int *lookup_b = plugin->lookup[2];
1366 int r, g, b, y, u, v, a;
1367 switch(input->get_color_model())
1370 PROCESS(unsigned char, 3)
1376 PROCESS(unsigned char, 4)
1382 PROCESS(uint16_t, 3)
1384 case BC_RGBA16161616:
1385 PROCESS(uint16_t, 4)
1388 PROCESS_YUV(unsigned char, 3, 0xff)
1391 PROCESS_YUV(unsigned char, 4, 0xff)
1394 PROCESS_YUV(uint16_t, 3, 0xffff)
1396 case BC_YUVA16161616:
1397 PROCESS_YUV(uint16_t, 4, 0xffff)
1408 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1411 : LoadServer(total_clients, total_packages)
1413 this->plugin = plugin;
1416 void HistogramEngine::init_packages()
1421 total_size = data->get_h();
1424 total_size = data->get_h();
1429 int package_size = (int)((float)total_size /
1430 get_total_packages() + 1);
1433 for(int i = 0; i < get_total_packages(); i++)
1435 HistogramPackage *package = (HistogramPackage*)get_package(i);
1436 package->start = total_size * i / get_total_packages();
1437 package->end = total_size * (i + 1) / get_total_packages();
1440 // Initialize clients here in case some don't get run.
1441 for(int i = 0; i < get_total_clients(); i++)
1443 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1444 for(int i = 0; i < HISTOGRAM_MODES; i++)
1445 bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1450 LoadClient* HistogramEngine::new_client()
1452 return new HistogramUnit(this, plugin);
1455 LoadPackage* HistogramEngine::new_package()
1457 return new HistogramPackage;
1460 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1463 this->operation = operation;
1464 this->do_value = do_value;
1465 LoadServer::process_packages();