4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "color3way.h"
28 #include "playback3d.h"
30 #include "aggregated.h"
31 #include "../interpolate/aggregated.h"
32 #include "../gamma/aggregated.h"
38 REGISTER_PLUGIN(Color3WayMain)
41 Color3WayConfig::Color3WayConfig()
43 for(int i = 0; i < SECTIONS; i++)
52 int Color3WayConfig::equivalent(Color3WayConfig &that)
54 for(int i = 0; i < SECTIONS; i++)
56 if(!EQUIV(hue_x[i], that.hue_x[i]) ||
57 !EQUIV(hue_y[i], that.hue_y[i]) ||
58 !EQUIV(value[i], that.value[i]) ||
59 !EQUIV(saturation[i], that.saturation[i])) return 0;
64 void Color3WayConfig::copy_from(Color3WayConfig &that)
66 for(int i = 0; i < SECTIONS; i++)
68 hue_x[i] = that.hue_x[i];
69 hue_y[i] = that.hue_y[i];
70 value[i] = that.value[i];
71 saturation[i] = that.saturation[i];
75 void Color3WayConfig::interpolate(Color3WayConfig &prev,
76 Color3WayConfig &next,
79 int64_t current_frame)
81 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
82 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
84 for(int i = 0; i < SECTIONS; i++)
86 hue_x[i] = prev.hue_x[i] * prev_scale + next.hue_x[i] * next_scale;
87 hue_y[i] = prev.hue_y[i] * prev_scale + next.hue_y[i] * next_scale;
88 value[i] = prev.value[i] * prev_scale + next.value[i] * next_scale;
89 saturation[i] = prev.saturation[i] * prev_scale + next.saturation[i] * next_scale;
94 void Color3WayConfig::boundaries()
96 for(int i = 0; i < SECTIONS; i++)
98 float point_radius = sqrt(SQR(hue_x[i]) + SQR(hue_y[i]));
101 float angle = atan2(hue_x[i],
103 hue_x[i] = sin(angle);
104 hue_y[i] = cos(angle);
109 void Color3WayConfig::copy_to_all(int section)
111 for(int i = 0; i < SECTIONS; i++)
113 hue_x[i] = hue_x[section];
114 hue_y[i] = hue_y[section];
115 value[i] = value[section];
116 saturation[i] = saturation[section];
134 Color3WayPackage::Color3WayPackage()
144 Color3WayUnit::Color3WayUnit(Color3WayMain *plugin,
145 Color3WayEngine *server)
148 this->plugin = plugin;
151 // Lower = sharper curve
152 #define SHADOW_GAMMA 32.0
153 #define HIGHLIGHT_GAMMA 32.0
154 // Keep value == 0 from blowing up
155 #define FUDGE (1.0 / 256.0)
156 // Scale curve from 0 - 1
157 #define SHADOW_BORDER (1.0 / ((1.0 / SHADOW_GAMMA + FUDGE) / FUDGE))
158 #define HIGHLIGHT_BORDER (1.0 / ((1.0 / HIGHLIGHT_GAMMA + FUDGE) / FUDGE))
160 #define SHADOW_CURVE(value) \
161 (((1.0 / (((value) / SHADOW_GAMMA + FUDGE) / FUDGE)) - SHADOW_BORDER) / (1.0 - SHADOW_BORDER))
163 #define SHADOW_LINEAR(value) (1.0 - (value))
165 #define HIGHLIGHT_CURVE(value) \
166 (((1.0 / (((1.0 - value) / HIGHLIGHT_GAMMA + FUDGE) / FUDGE)) - HIGHLIGHT_BORDER) / (1.0 - HIGHLIGHT_BORDER))
168 #define HIGHLIGHT_LINEAR(value) \
171 #define MIDTONE_CURVE(value, factor) \
173 (1.0 - SHADOW_LINEAR(value) - HIGHLIGHT_CURVE(value)) : \
174 (1.0 - SHADOW_CURVE(value) - HIGHLIGHT_LINEAR(value)))
176 #define TOTAL_TRANSFER(value, factor) \
177 (factor[SHADOWS] * SHADOW_LINEAR(value) + \
178 factor[MIDTONES] * MIDTONE_CURVE(value, factor[MIDTONES]) + \
179 factor[HIGHLIGHTS] * HIGHLIGHT_LINEAR(value))
181 #define PROCESS_PIXEL(r, g, b) \
183 r = r + TOTAL_TRANSFER(r, r_factor); \
184 g = g + TOTAL_TRANSFER(g, g_factor); \
185 b = b + TOTAL_TRANSFER(b, b_factor); \
186 /* Apply saturation/value */ \
188 HSV::rgb_to_hsv(r, g, b, h, s, v); \
189 v += TOTAL_TRANSFER(v, v_factor); \
190 s += TOTAL_TRANSFER(s, s_factor); \
192 HSV::hsv_to_rgb(r, g, b, h, s, v);
195 #define PROCESS(type, max, components, is_yuv) \
197 type *in = (type*)plugin->get_input()->get_rows()[i]; \
198 type *out = (type*)plugin->get_input()->get_rows()[i]; \
199 for(int j = 0; j < w; j++) \
201 /* Convert to RGB float */ \
207 YUV::yuv_to_rgb_f(r, \
210 (float)in[0] / max, \
211 (float)in[1] / max - 0.5, \
212 (float)in[2] / max - 0.5); \
217 r = (float)*in++ / max; \
218 g = (float)*in++ / max; \
219 b = (float)*in++ / max; \
222 PROCESS_PIXEL(r, g, b) \
224 /* Convert to project colormodel */ \
228 YUV::rgb_to_yuv_f(r, g, b, y, u, v); \
239 *out++ = (type)(r * max); \
240 *out++ = (type)(g * max); \
241 *out++ = (type)(b * max); \
242 if(components == 4) \
250 #define CALCULATE_FACTORS(s_out, v_out, s_in, v_in) \
256 void Color3WayUnit::process_package(LoadPackage *package)
258 Color3WayPackage *pkg = (Color3WayPackage*)package;
259 int w = plugin->get_input()->get_w();
261 float r_factor[SECTIONS];
262 float g_factor[SECTIONS];
263 float b_factor[SECTIONS];
264 float s_factor[SECTIONS];
265 float v_factor[SECTIONS];
268 for(int i = 0; i < SECTIONS; i++)
270 plugin->calculate_factors(&r_factor[i], &g_factor[i], &b_factor[i], i);
271 CALCULATE_FACTORS(s_factor[i],
273 plugin->config.saturation[i],
274 plugin->config.value[i])
275 // printf("Color3WayUnit::process_package %d %f %f %f %f %f\n",
286 for(int i = pkg->row1; i < pkg->row2; i++)
288 switch(plugin->get_input()->get_color_model())
291 PROCESS(unsigned char, 0xff, 3, 0)
294 PROCESS(unsigned char, 0xff, 4, 0)
297 PROCESS(unsigned char, 0xff, 3, 1)
300 PROCESS(unsigned char, 0xff, 4, 1)
303 PROCESS(float, 1.0, 3, 0)
306 PROCESS(float, 1.0, 4, 0)
317 Color3WayEngine::Color3WayEngine(Color3WayMain *plugin, int cpus)
318 : LoadServer(cpus, cpus)
320 this->plugin = plugin;
323 Color3WayEngine::~Color3WayEngine()
327 void Color3WayEngine::init_packages()
331 printf("Color3WayEngine::init_packages %d\n", __LINE__);
332 for(int i = 0; i <= 255; i++)
334 printf("%f\t%f\t%f\n",
335 SHADOW_CURVE((float)i / 255),
336 MIDTONE_CURVE((float)i / 255),
337 HIGHLIGHT_CURVE((float)i / 255));
341 for(int i = 0; i < LoadServer::get_total_packages(); i++)
343 Color3WayPackage *pkg = (Color3WayPackage*)get_package(i);
344 pkg->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages();
345 pkg->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages();
350 LoadClient* Color3WayEngine::new_client()
352 return new Color3WayUnit(plugin, this);
355 LoadPackage* Color3WayEngine::new_package()
357 return new Color3WayPackage;
369 Color3WayMain::Color3WayMain(PluginServer *server)
370 : PluginVClient(server)
372 need_reconfigure = 1;
376 for(int i = 0; i < SECTIONS; i++) copy_to_all[i] = 0;
379 Color3WayMain::~Color3WayMain()
385 const char* Color3WayMain::plugin_title() { return _("Color 3 Way"); }
386 int Color3WayMain::is_realtime() { return 1; }
389 int Color3WayMain::reconfigure()
395 void Color3WayMain::process_pixel(float *r,
404 float r_factor[SECTIONS];
405 float g_factor[SECTIONS];
406 float b_factor[SECTIONS];
407 float s_factor[SECTIONS];
408 float v_factor[SECTIONS];
409 for(int i = 0; i < SECTIONS; i++)
411 calculate_factors(r_factor + i,
416 CALCULATE_FACTORS(s_factor[i], v_factor[i], 0, 0)
419 PROCESS_PIXEL(r_in, g_in, b_in);
425 void Color3WayMain::calculate_factors(float *r,
431 // float h = atan2(-x, -y) * 360 / 2 / M_PI + 180;
433 // float s = sqrt(SQR(x) + SQR(y));
434 // HSV::hsv_to_rgb(*r, *g, *b, h, s, v);
435 //printf("Color3WayMain::calculate_factors %d %f %f %f %f %f\n", __LINE__, x, y, h, s, v);
437 *r = sqrt(SQR(x) + SQR(y - -1));
438 *g = sqrt(SQR(x - -1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
439 *b = sqrt(SQR(x - 1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
446 void Color3WayMain::calculate_factors(float *r, float *g, float *b, int section)
448 calculate_factors(r, g, b, config.hue_x[section], config.hue_y[section]);
451 //printf("Color3WayMain::calculate_factors %d %f %f %f\n", __LINE__, *r, *g, *b);
460 LOAD_CONFIGURATION_MACRO(Color3WayMain, Color3WayConfig)
461 NEW_WINDOW_MACRO(Color3WayMain, Color3WayWindow)
467 int Color3WayMain::process_buffer(VFrame *frame,
468 int64_t start_position,
471 need_reconfigure |= load_configuration();
473 if(!engine) engine = new Color3WayEngine(this,
475 PluginClient::smp + 1);
477 //printf("Color3WayMain::process_realtime 1 %d\n", need_reconfigure);
482 need_reconfigure = 0;
489 get_source_position(),
493 int aggregate_interpolate = 0;
494 int aggregate_gamma = 0;
495 get_aggregation(&aggregate_interpolate,
500 engine->process_packages();
507 void Color3WayMain::update_gui()
511 load_configuration();
512 ((Color3WayWindow*)thread->window)->lock_window("Color3WayMain::update_gui");
513 ((Color3WayWindow*)thread->window)->update();
514 ((Color3WayWindow*)thread->window)->unlock_window();
521 void Color3WayMain::save_data(KeyFrame *keyframe)
525 // cause data to be stored directly in text
526 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
527 output.tag.set_title("COLOR3WAY");
528 for(int i = 0; i < SECTIONS; i++)
530 char string[BCTEXTLEN];
531 sprintf(string, "HUE_X_%d", i);
532 output.tag.set_property(string, config.hue_x[i]);
533 sprintf(string, "HUE_Y_%d", i);
534 output.tag.set_property(string, config.hue_y[i]);
535 sprintf(string, "VALUE_%d", i);
536 output.tag.set_property(string, config.value[i]);
537 sprintf(string, "SATURATION_%d", i);
538 output.tag.set_property(string, config.saturation[i]);
541 sprintf(string, "COPY_TO_ALL_%d", i);
542 output.tag.set_property(string, copy_to_all[i]);
548 output.tag.set_property("W", w);
549 output.tag.set_property("H", h);
553 output.tag.set_title("/COLOR3WAY");
555 output.append_newline();
556 output.terminate_string();
559 void Color3WayMain::read_data(KeyFrame *keyframe)
563 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
569 result = input.read_tag();
573 if(input.tag.title_is("COLOR3WAY"))
575 for(int i = 0; i < SECTIONS; i++)
577 char string[BCTEXTLEN];
578 sprintf(string, "HUE_X_%d", i);
579 config.hue_x[i] = input.tag.get_property(string, config.hue_x[i]);
580 sprintf(string, "HUE_Y_%d", i);
581 config.hue_y[i] = input.tag.get_property(string, config.hue_y[i]);
582 sprintf(string, "VALUE_%d", i);
583 config.value[i] = input.tag.get_property(string, config.value[i]);
584 sprintf(string, "SATURATION_%d", i);
585 config.saturation[i] = input.tag.get_property(string, config.saturation[i]);
589 sprintf(string, "COPY_TO_ALL_%d", i);
590 copy_to_all[i] = input.tag.get_property(string, copy_to_all[i]);
596 w = input.tag.get_property("W", w);
597 h = input.tag.get_property("H", h);
604 void Color3WayMain::get_aggregation(int *aggregate_interpolate,
605 int *aggregate_gamma)
607 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
608 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
610 *aggregate_interpolate = 1;
611 *aggregate_gamma = 1;
614 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
616 *aggregate_interpolate = 1;
619 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
621 *aggregate_gamma = 1;
625 int Color3WayMain::handle_opengl()
629 get_output()->to_texture();
630 get_output()->enable_opengl();
632 unsigned int shader = 0;
633 const char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
634 int current_shader = 0;
635 int aggregate_interpolate = 0;
636 int aggregate_gamma = 0;
638 get_aggregation(&aggregate_interpolate,
641 printf("Color3WayMain::handle_opengl %d %d\n", aggregate_interpolate, aggregate_gamma);
642 if(aggregate_interpolate)
643 INTERPOLATE_COMPILE(shader_stack, current_shader)
646 GAMMA_COMPILE(shader_stack, current_shader, aggregate_interpolate)
648 COLORBALANCE_COMPILE(shader_stack,
650 aggregate_gamma || aggregate_interpolate)
652 shader = VFrame::make_shader(0,
665 glUseProgram(shader);
666 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
668 if(aggregate_interpolate) INTERPOLATE_UNIFORMS(shader);
669 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
671 COLORBALANCE_UNIFORMS(shader);
675 get_output()->init_screen();
676 get_output()->bind_texture(0);
677 get_output()->draw_texture();
679 get_output()->set_opengl_state(VFrame::SCREEN);