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"
34 REGISTER_PLUGIN(Color3WayMain)
37 Color3WayConfig::Color3WayConfig()
39 for(int i = 0; i < SECTIONS; i++)
48 int Color3WayConfig::equivalent(Color3WayConfig &that)
50 for(int i = 0; i < SECTIONS; i++)
52 if(!EQUIV(hue_x[i], that.hue_x[i]) ||
53 !EQUIV(hue_y[i], that.hue_y[i]) ||
54 !EQUIV(value[i], that.value[i]) ||
55 !EQUIV(saturation[i], that.saturation[i])) return 0;
60 void Color3WayConfig::copy_from(Color3WayConfig &that)
62 for(int i = 0; i < SECTIONS; i++)
64 hue_x[i] = that.hue_x[i];
65 hue_y[i] = that.hue_y[i];
66 value[i] = that.value[i];
67 saturation[i] = that.saturation[i];
71 void Color3WayConfig::interpolate(Color3WayConfig &prev,
72 Color3WayConfig &next,
75 int64_t current_frame)
77 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
78 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
80 for(int i = 0; i < SECTIONS; i++)
82 hue_x[i] = prev.hue_x[i] * prev_scale + next.hue_x[i] * next_scale;
83 hue_y[i] = prev.hue_y[i] * prev_scale + next.hue_y[i] * next_scale;
84 value[i] = prev.value[i] * prev_scale + next.value[i] * next_scale;
85 saturation[i] = prev.saturation[i] * prev_scale + next.saturation[i] * next_scale;
90 void Color3WayConfig::boundaries()
92 for(int i = 0; i < SECTIONS; i++)
94 float point_radius = sqrt(SQR(hue_x[i]) + SQR(hue_y[i]));
97 float angle = atan2(hue_x[i],
99 hue_x[i] = sin(angle);
100 hue_y[i] = cos(angle);
105 void Color3WayConfig::copy_to_all(int section)
107 for(int i = 0; i < SECTIONS; i++)
109 hue_x[i] = hue_x[section];
110 hue_y[i] = hue_y[section];
111 value[i] = value[section];
112 saturation[i] = saturation[section];
130 Color3WayPackage::Color3WayPackage()
140 Color3WayUnit::Color3WayUnit(Color3WayMain *plugin,
141 Color3WayEngine *server)
144 this->plugin = plugin;
147 // Lower = sharper curve
148 #define SHADOW_GAMMA 32.0
149 #define HIGHLIGHT_GAMMA 32.0
150 // Keep value == 0 from blowing up
151 #define FUDGE (1.0 / 256.0)
152 // Scale curve from 0 - 1
153 #define SHADOW_BORDER (1.0 / ((1.0 / SHADOW_GAMMA + FUDGE) / FUDGE))
154 #define HIGHLIGHT_BORDER (1.0 / ((1.0 / HIGHLIGHT_GAMMA + FUDGE) / FUDGE))
156 #define SHADOW_CURVE(value) \
157 (((1.0 / (((value) / SHADOW_GAMMA + FUDGE) / FUDGE)) - SHADOW_BORDER) / (1.0 - SHADOW_BORDER))
159 #define SHADOW_LINEAR(value) (1.0 - (value))
161 #define HIGHLIGHT_CURVE(value) \
162 (((1.0 / (((1.0 - value) / HIGHLIGHT_GAMMA + FUDGE) / FUDGE)) - HIGHLIGHT_BORDER) / (1.0 - HIGHLIGHT_BORDER))
164 #define HIGHLIGHT_LINEAR(value) \
167 #define MIDTONE_CURVE(value, factor) \
169 (1.0 - SHADOW_LINEAR(value) - HIGHLIGHT_CURVE(value)) : \
170 (1.0 - SHADOW_CURVE(value) - HIGHLIGHT_LINEAR(value)))
172 #define TOTAL_TRANSFER(value, factor) \
173 (factor[SHADOWS] * SHADOW_LINEAR(value) + \
174 factor[MIDTONES] * MIDTONE_CURVE(value, factor[MIDTONES]) + \
175 factor[HIGHLIGHTS] * HIGHLIGHT_LINEAR(value))
177 #define PROCESS_PIXEL(r, g, b) \
179 r = r + TOTAL_TRANSFER(r, r_factor); \
180 g = g + TOTAL_TRANSFER(g, g_factor); \
181 b = b + TOTAL_TRANSFER(b, b_factor); \
182 r = CLAMP(r,0,1); g = CLAMP(g,0,1); b = CLAMP(b,0,1); \
183 /* Apply saturation/value */ \
185 HSV::rgb_to_hsv(r, g, b, h, s, v); \
186 v += TOTAL_TRANSFER(v, v_factor); \
187 s += TOTAL_TRANSFER(s, s_factor); \
188 s = CLAMP(s,0,1); v = CLAMP(v,0,1); \
189 HSV::hsv_to_rgb(r, g, b, h, s, v);
192 #define PROCESS(type, max, components, is_yuv) \
194 type *in = (type*)plugin->get_input()->get_rows()[i]; \
195 type *out = (type*)plugin->get_input()->get_rows()[i]; \
196 for(int j = 0; j < w; j++) { \
197 /* Convert to RGB float */ \
200 r = (float)in[0] / max; \
201 g = (float)in[1] / max; \
202 b = (float)in[2] / max; \
205 YUV::yuv.yuv_to_rgb_f(r, g, b, in[0], in[1], in[2]); \
207 PROCESS_PIXEL(r, g, b) \
210 /* Convert to project colormodel */ \
216 out[0] = (type)(r * max); \
217 out[1] = (type)(g * max); \
218 out[2] = (type)(b * max); \
221 YUV::yuv.rgb_to_yuv_f(r, g, b, out[0], out[1], out[2]); \
228 #define CALCULATE_FACTORS(s_out, v_out, s_in, v_in) \
234 void Color3WayUnit::process_package(LoadPackage *package)
236 Color3WayPackage *pkg = (Color3WayPackage*)package;
237 int w = plugin->get_input()->get_w();
239 float r_factor[SECTIONS];
240 float g_factor[SECTIONS];
241 float b_factor[SECTIONS];
242 float s_factor[SECTIONS];
243 float v_factor[SECTIONS];
246 for(int i = 0; i < SECTIONS; i++)
248 plugin->calculate_factors(&r_factor[i], &g_factor[i], &b_factor[i], i);
249 CALCULATE_FACTORS(s_factor[i],
251 plugin->config.saturation[i],
252 plugin->config.value[i])
253 // printf("Color3WayUnit::process_package %d %f %f %f %f %f\n",
264 for(int i = pkg->row1; i < pkg->row2; i++)
266 switch(plugin->get_input()->get_color_model())
269 PROCESS(unsigned char, 0xff, 3, 0)
272 PROCESS(unsigned char, 0xff, 4, 0)
275 PROCESS(unsigned char, 0xff, 3, 1)
278 PROCESS(unsigned char, 0xff, 4, 1)
281 PROCESS(float, 1.0, 3, 0)
284 PROCESS(float, 1.0, 4, 0)
295 Color3WayEngine::Color3WayEngine(Color3WayMain *plugin, int cpus)
296 : LoadServer(cpus, cpus)
298 this->plugin = plugin;
301 Color3WayEngine::~Color3WayEngine()
305 void Color3WayEngine::init_packages()
309 printf("Color3WayEngine::init_packages %d\n", __LINE__);
310 for(int i = 0; i <= 255; i++)
312 printf("%f\t%f\t%f\n",
313 SHADOW_CURVE((float)i / 255),
314 MIDTONE_CURVE((float)i / 255),
315 HIGHLIGHT_CURVE((float)i / 255));
319 for(int i = 0; i < LoadServer::get_total_packages(); i++)
321 Color3WayPackage *pkg = (Color3WayPackage*)get_package(i);
322 pkg->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages();
323 pkg->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages();
328 LoadClient* Color3WayEngine::new_client()
330 return new Color3WayUnit(plugin, this);
333 LoadPackage* Color3WayEngine::new_package()
335 return new Color3WayPackage;
347 Color3WayMain::Color3WayMain(PluginServer *server)
348 : PluginVClient(server)
350 need_reconfigure = 1;
354 for(int i = 0; i < SECTIONS; i++) copy_to_all[i] = 0;
357 Color3WayMain::~Color3WayMain()
363 const char* Color3WayMain::plugin_title() { return N_("Color 3 Way"); }
364 int Color3WayMain::is_realtime() { return 1; }
367 int Color3WayMain::reconfigure()
373 void Color3WayMain::process_pixel(float *r,
382 float r_factor[SECTIONS];
383 float g_factor[SECTIONS];
384 float b_factor[SECTIONS];
385 float s_factor[SECTIONS];
386 float v_factor[SECTIONS];
387 for(int i = 0; i < SECTIONS; i++)
389 calculate_factors(r_factor + i,
394 CALCULATE_FACTORS(s_factor[i], v_factor[i], 0, 0)
397 PROCESS_PIXEL(r_in, g_in, b_in);
403 void Color3WayMain::calculate_factors(float *r,
409 // float h = atan2(-x, -y) * 360 / 2 / M_PI + 180;
411 // float s = sqrt(SQR(x) + SQR(y));
412 // HSV::hsv_to_rgb(*r, *g, *b, h, s, v);
413 //printf("Color3WayMain::calculate_factors %d %f %f %f %f %f\n", __LINE__, x, y, h, s, v);
415 *r = sqrt(SQR(x) + SQR(y - -1));
416 *g = sqrt(SQR(x - -1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
417 *b = sqrt(SQR(x - 1.0 / ROOT_2) + SQR(y - 1.0 / ROOT_2));
424 void Color3WayMain::calculate_factors(float *r, float *g, float *b, int section)
426 calculate_factors(r, g, b, config.hue_x[section], config.hue_y[section]);
429 //printf("Color3WayMain::calculate_factors %d %f %f %f\n", __LINE__, *r, *g, *b);
438 LOAD_CONFIGURATION_MACRO(Color3WayMain, Color3WayConfig)
439 NEW_WINDOW_MACRO(Color3WayMain, Color3WayWindow)
445 int Color3WayMain::process_buffer(VFrame *frame,
446 int64_t start_position,
449 need_reconfigure |= load_configuration();
451 if(!engine) engine = new Color3WayEngine(this,
453 PluginClient::smp + 1);
455 //printf("Color3WayMain::process_realtime 1 %d\n", need_reconfigure);
460 need_reconfigure = 0;
467 get_source_position(),
471 int aggregate_interpolate = 0;
472 int aggregate_gamma = 0;
473 get_aggregation(&aggregate_interpolate,
476 engine->process_packages();
482 void Color3WayMain::update_gui()
486 load_configuration();
487 ((Color3WayWindow*)thread->window)->lock_window("Color3WayMain::update_gui");
488 ((Color3WayWindow*)thread->window)->update();
489 ((Color3WayWindow*)thread->window)->unlock_window();
496 void Color3WayMain::save_data(KeyFrame *keyframe)
500 // cause data to be stored directly in text
501 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
502 output.tag.set_title("COLOR3WAY");
503 for(int i = 0; i < SECTIONS; i++)
505 char string[BCTEXTLEN];
506 sprintf(string, "HUE_X_%d", i);
507 output.tag.set_property(string, config.hue_x[i]);
508 sprintf(string, "HUE_Y_%d", i);
509 output.tag.set_property(string, config.hue_y[i]);
510 sprintf(string, "VALUE_%d", i);
511 output.tag.set_property(string, config.value[i]);
512 sprintf(string, "SATURATION_%d", i);
513 output.tag.set_property(string, config.saturation[i]);
516 sprintf(string, "COPY_TO_ALL_%d", i);
517 output.tag.set_property(string, copy_to_all[i]);
523 output.tag.set_property("W", w);
524 output.tag.set_property("H", h);
528 output.tag.set_title("/COLOR3WAY");
530 output.append_newline();
531 output.terminate_string();
534 void Color3WayMain::read_data(KeyFrame *keyframe)
538 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
544 result = input.read_tag();
548 if(input.tag.title_is("COLOR3WAY"))
550 for(int i = 0; i < SECTIONS; i++)
552 char string[BCTEXTLEN];
553 sprintf(string, "HUE_X_%d", i);
554 config.hue_x[i] = input.tag.get_property(string, config.hue_x[i]);
555 sprintf(string, "HUE_Y_%d", i);
556 config.hue_y[i] = input.tag.get_property(string, config.hue_y[i]);
557 sprintf(string, "VALUE_%d", i);
558 config.value[i] = input.tag.get_property(string, config.value[i]);
559 sprintf(string, "SATURATION_%d", i);
560 config.saturation[i] = input.tag.get_property(string, config.saturation[i]);
564 sprintf(string, "COPY_TO_ALL_%d", i);
565 copy_to_all[i] = input.tag.get_property(string, copy_to_all[i]);
571 w = input.tag.get_property("W", w);
572 h = input.tag.get_property("H", h);
579 void Color3WayMain::get_aggregation(int *aggregate_interpolate,
580 int *aggregate_gamma)
582 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
583 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
585 *aggregate_interpolate = 1;
586 *aggregate_gamma = 1;
589 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
591 *aggregate_interpolate = 1;
594 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
596 *aggregate_gamma = 1;