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.yuv_to_rgb_f(r, g, b, \
208 (float)in[0] / max, \
209 (float)in[1] / max - 0.5, \
210 (float)in[2] / max - 0.5); \
215 r = (float)*in++ / max; \
216 g = (float)*in++ / max; \
217 b = (float)*in++ / max; \
220 PROCESS_PIXEL(r, g, b) \
222 /* Convert to project colormodel */ \
226 YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v); \
237 *out++ = (type)(r * max); \
238 *out++ = (type)(g * max); \
239 *out++ = (type)(b * max); \
240 if(components == 4) \
248 #define CALCULATE_FACTORS(s_out, v_out, s_in, v_in) \
254 void Color3WayUnit::process_package(LoadPackage *package)
256 Color3WayPackage *pkg = (Color3WayPackage*)package;
257 int w = plugin->get_input()->get_w();
259 float r_factor[SECTIONS];
260 float g_factor[SECTIONS];
261 float b_factor[SECTIONS];
262 float s_factor[SECTIONS];
263 float v_factor[SECTIONS];
266 for(int i = 0; i < SECTIONS; i++)
268 plugin->calculate_factors(&r_factor[i], &g_factor[i], &b_factor[i], i);
269 CALCULATE_FACTORS(s_factor[i],
271 plugin->config.saturation[i],
272 plugin->config.value[i])
273 // printf("Color3WayUnit::process_package %d %f %f %f %f %f\n",
284 for(int i = pkg->row1; i < pkg->row2; i++)
286 switch(plugin->get_input()->get_color_model())
289 PROCESS(unsigned char, 0xff, 3, 0)
292 PROCESS(unsigned char, 0xff, 4, 0)
295 PROCESS(unsigned char, 0xff, 3, 1)
298 PROCESS(unsigned char, 0xff, 4, 1)
301 PROCESS(float, 1.0, 3, 0)
304 PROCESS(float, 1.0, 4, 0)
315 Color3WayEngine::Color3WayEngine(Color3WayMain *plugin, int cpus)
316 : LoadServer(cpus, cpus)
318 this->plugin = plugin;
321 Color3WayEngine::~Color3WayEngine()
325 void Color3WayEngine::init_packages()
329 printf("Color3WayEngine::init_packages %d\n", __LINE__);
330 for(int i = 0; i <= 255; i++)
332 printf("%f\t%f\t%f\n",
333 SHADOW_CURVE((float)i / 255),
334 MIDTONE_CURVE((float)i / 255),
335 HIGHLIGHT_CURVE((float)i / 255));
339 for(int i = 0; i < LoadServer::get_total_packages(); i++)
341 Color3WayPackage *pkg = (Color3WayPackage*)get_package(i);
342 pkg->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages();
343 pkg->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages();
348 LoadClient* Color3WayEngine::new_client()
350 return new Color3WayUnit(plugin, this);
353 LoadPackage* Color3WayEngine::new_package()
355 return new Color3WayPackage;
367 Color3WayMain::Color3WayMain(PluginServer *server)
368 : PluginVClient(server)
370 need_reconfigure = 1;
374 for(int i = 0; i < SECTIONS; i++) copy_to_all[i] = 0;
377 Color3WayMain::~Color3WayMain()
383 const char* Color3WayMain::plugin_title() { return _("Color 3 Way"); }
384 int Color3WayMain::is_realtime() { return 1; }
387 int Color3WayMain::reconfigure()
393 void Color3WayMain::process_pixel(float *r,
402 float r_factor[SECTIONS];
403 float g_factor[SECTIONS];
404 float b_factor[SECTIONS];
405 float s_factor[SECTIONS];
406 float v_factor[SECTIONS];
407 for(int i = 0; i < SECTIONS; i++)
409 calculate_factors(r_factor + i,
414 CALCULATE_FACTORS(s_factor[i], v_factor[i], 0, 0)
417 PROCESS_PIXEL(r_in, g_in, b_in);
423 void Color3WayMain::calculate_factors(float *r,
429 // float h = atan2(-x, -y) * 360 / 2 / M_PI + 180;
431 // float s = sqrt(SQR(x) + SQR(y));
432 // HSV::hsv_to_rgb(*r, *g, *b, h, s, v);
433 //printf("Color3WayMain::calculate_factors %d %f %f %f %f %f\n", __LINE__, x, y, h, s, v);
435 *r = sqrt(SQR(x) + SQR(y - -1));
436 *g = sqrt(SQR(x - -1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
437 *b = sqrt(SQR(x - 1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
444 void Color3WayMain::calculate_factors(float *r, float *g, float *b, int section)
446 calculate_factors(r, g, b, config.hue_x[section], config.hue_y[section]);
449 //printf("Color3WayMain::calculate_factors %d %f %f %f\n", __LINE__, *r, *g, *b);
458 LOAD_CONFIGURATION_MACRO(Color3WayMain, Color3WayConfig)
459 NEW_WINDOW_MACRO(Color3WayMain, Color3WayWindow)
465 int Color3WayMain::process_buffer(VFrame *frame,
466 int64_t start_position,
469 need_reconfigure |= load_configuration();
471 if(!engine) engine = new Color3WayEngine(this,
473 PluginClient::smp + 1);
475 //printf("Color3WayMain::process_realtime 1 %d\n", need_reconfigure);
480 need_reconfigure = 0;
487 get_source_position(),
491 int aggregate_interpolate = 0;
492 int aggregate_gamma = 0;
493 get_aggregation(&aggregate_interpolate,
498 engine->process_packages();
505 void Color3WayMain::update_gui()
509 load_configuration();
510 ((Color3WayWindow*)thread->window)->lock_window("Color3WayMain::update_gui");
511 ((Color3WayWindow*)thread->window)->update();
512 ((Color3WayWindow*)thread->window)->unlock_window();
519 void Color3WayMain::save_data(KeyFrame *keyframe)
523 // cause data to be stored directly in text
524 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
525 output.tag.set_title("COLOR3WAY");
526 for(int i = 0; i < SECTIONS; i++)
528 char string[BCTEXTLEN];
529 sprintf(string, "HUE_X_%d", i);
530 output.tag.set_property(string, config.hue_x[i]);
531 sprintf(string, "HUE_Y_%d", i);
532 output.tag.set_property(string, config.hue_y[i]);
533 sprintf(string, "VALUE_%d", i);
534 output.tag.set_property(string, config.value[i]);
535 sprintf(string, "SATURATION_%d", i);
536 output.tag.set_property(string, config.saturation[i]);
539 sprintf(string, "COPY_TO_ALL_%d", i);
540 output.tag.set_property(string, copy_to_all[i]);
546 output.tag.set_property("W", w);
547 output.tag.set_property("H", h);
551 output.tag.set_title("/COLOR3WAY");
553 output.append_newline();
554 output.terminate_string();
557 void Color3WayMain::read_data(KeyFrame *keyframe)
561 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
567 result = input.read_tag();
571 if(input.tag.title_is("COLOR3WAY"))
573 for(int i = 0; i < SECTIONS; i++)
575 char string[BCTEXTLEN];
576 sprintf(string, "HUE_X_%d", i);
577 config.hue_x[i] = input.tag.get_property(string, config.hue_x[i]);
578 sprintf(string, "HUE_Y_%d", i);
579 config.hue_y[i] = input.tag.get_property(string, config.hue_y[i]);
580 sprintf(string, "VALUE_%d", i);
581 config.value[i] = input.tag.get_property(string, config.value[i]);
582 sprintf(string, "SATURATION_%d", i);
583 config.saturation[i] = input.tag.get_property(string, config.saturation[i]);
587 sprintf(string, "COPY_TO_ALL_%d", i);
588 copy_to_all[i] = input.tag.get_property(string, copy_to_all[i]);
594 w = input.tag.get_property("W", w);
595 h = input.tag.get_property("H", h);
602 void Color3WayMain::get_aggregation(int *aggregate_interpolate,
603 int *aggregate_gamma)
605 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
606 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
608 *aggregate_interpolate = 1;
609 *aggregate_gamma = 1;
612 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
614 *aggregate_interpolate = 1;
617 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
619 *aggregate_gamma = 1;
623 int Color3WayMain::handle_opengl()
627 get_output()->to_texture();
628 get_output()->enable_opengl();
630 unsigned int shader = 0;
631 const char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
632 int current_shader = 0;
633 int aggregate_interpolate = 0;
634 int aggregate_gamma = 0;
636 get_aggregation(&aggregate_interpolate,
639 printf("Color3WayMain::handle_opengl %d %d\n", aggregate_interpolate, aggregate_gamma);
640 if(aggregate_interpolate)
641 INTERPOLATE_COMPILE(shader_stack, current_shader)
644 GAMMA_COMPILE(shader_stack, current_shader, aggregate_interpolate)
646 COLORBALANCE_COMPILE(shader_stack,
648 aggregate_gamma || aggregate_interpolate)
650 shader = VFrame::make_shader(0,
663 glUseProgram(shader);
664 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
666 if(aggregate_interpolate) INTERPOLATE_UNIFORMS(shader);
667 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
669 COLORBALANCE_UNIFORMS(shader);
673 get_output()->init_screen();
674 get_output()->bind_texture(0);
675 get_output()->draw_texture();
677 get_output()->set_opengl_state(VFrame::SCREEN);