add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / color3way / color3way.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 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
23
24 #include "filexml.h"
25 #include "color3way.h"
26 #include "bchash.h"
27 #include "language.h"
28 #include "playback3d.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33
34 REGISTER_PLUGIN(Color3WayMain)
35
36
37 Color3WayConfig::Color3WayConfig()
38 {
39         for(int i = 0; i < SECTIONS; i++)
40         {
41                 hue_x[i] = 0.0;
42                 hue_y[i] = 0.0;
43                 value[i] = 0.0;
44                 saturation[i] = 0.0;
45         }
46 }
47
48 int Color3WayConfig::equivalent(Color3WayConfig &that)
49 {
50         for(int i = 0; i < SECTIONS; i++)
51         {
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;
56         }
57         return 1;
58 }
59
60 void Color3WayConfig::copy_from(Color3WayConfig &that)
61 {
62         for(int i = 0; i < SECTIONS; i++)
63         {
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];
68         }
69 }
70
71 void Color3WayConfig::interpolate(Color3WayConfig &prev,
72         Color3WayConfig &next,
73         int64_t prev_frame,
74         int64_t next_frame,
75         int64_t current_frame)
76 {
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);
79
80         for(int i = 0; i < SECTIONS; i++)
81         {
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;
86         }
87 }
88
89
90 void Color3WayConfig::boundaries()
91 {
92         for(int i = 0; i < SECTIONS; i++)
93         {
94                 float point_radius = sqrt(SQR(hue_x[i]) + SQR(hue_y[i]));
95                 if(point_radius > 1)
96                 {
97                         float angle = atan2(hue_x[i],
98                                                 hue_y[i]);
99                         hue_x[i] = sin(angle);
100                         hue_y[i] = cos(angle);
101                 }
102         }
103 }
104
105 void Color3WayConfig::copy_to_all(int section)
106 {
107         for(int i = 0; i < SECTIONS; i++)
108         {
109                 hue_x[i] = hue_x[section];
110                 hue_y[i] = hue_y[section];
111                 value[i] = value[section];
112                 saturation[i] = saturation[section];
113         }
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 Color3WayPackage::Color3WayPackage()
131  : LoadPackage()
132 {
133 }
134
135
136
137
138
139
140 Color3WayUnit::Color3WayUnit(Color3WayMain *plugin,
141         Color3WayEngine *server)
142  : LoadClient(server)
143 {
144         this->plugin = plugin;
145 }
146
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))
155
156 #define SHADOW_CURVE(value) \
157         (((1.0 / (((value) / SHADOW_GAMMA + FUDGE) / FUDGE)) - SHADOW_BORDER) / (1.0 - SHADOW_BORDER))
158
159 #define SHADOW_LINEAR(value) (1.0 - (value))
160
161 #define HIGHLIGHT_CURVE(value) \
162         (((1.0 / (((1.0 - value) / HIGHLIGHT_GAMMA + FUDGE) / FUDGE)) - HIGHLIGHT_BORDER) / (1.0 - HIGHLIGHT_BORDER))
163
164 #define HIGHLIGHT_LINEAR(value) \
165         (value)
166
167 #define MIDTONE_CURVE(value, factor) \
168         ((factor) <= 0 ? \
169         (1.0 - SHADOW_LINEAR(value) - HIGHLIGHT_CURVE(value)) : \
170         (1.0 - SHADOW_CURVE(value) - HIGHLIGHT_LINEAR(value)))
171
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))
176
177 #define PROCESS_PIXEL(r, g, b) \
178 /* Apply hue */ \
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 */ \
184         float h, s, v; \
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);
190
191
192 #define PROCESS(type, max, components, is_yuv) \
193 { \
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 */ \
198                 float r, g, b; \
199                 if( !is_yuv ) { \
200                         r = (float)in[0] / max; \
201                         g = (float)in[1] / max; \
202                         b = (float)in[2] / max; \
203                 } \
204                 else \
205                         YUV::yuv.yuv_to_rgb_f(r, g, b, in[0], in[1], in[2]); \
206  \
207                 PROCESS_PIXEL(r, g, b) \
208  \
209                 if( !is_yuv ) { \
210 /* Convert to project colormodel */ \
211                         if(max == 0xff) { \
212                                 CLAMP(r, 0, 1); \
213                                 CLAMP(g, 0, 1); \
214                                 CLAMP(b, 0, 1); \
215                         } \
216                         out[0] = (type)(r * max); \
217                         out[1] = (type)(g * max); \
218                         out[2] = (type)(b * max); \
219                 } \
220                 else \
221                         YUV::yuv.rgb_to_yuv_f(r, g, b, out[0], out[1], out[2]); \
222  \
223                 in  += components; \
224                 out += components; \
225         } \
226 }
227
228 #define CALCULATE_FACTORS(s_out, v_out, s_in, v_in) \
229         s_out = s_in; \
230         v_out = v_in;
231
232
233
234 void Color3WayUnit::process_package(LoadPackage *package)
235 {
236         Color3WayPackage *pkg = (Color3WayPackage*)package;
237         int w = plugin->get_input()->get_w();
238
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];
244
245
246         for(int i = 0; i < SECTIONS; i++)
247         {
248                 plugin->calculate_factors(&r_factor[i], &g_factor[i], &b_factor[i], i);
249                 CALCULATE_FACTORS(s_factor[i],
250                         v_factor[i],
251                         plugin->config.saturation[i],
252                         plugin->config.value[i])
253 // printf("Color3WayUnit::process_package %d %f %f %f %f %f\n",
254 // __LINE__,
255 // r_factor[i],
256 // g_factor[i],
257 // b_factor[i],
258 // s_factor[i],
259 // v_factor[i]);
260         }
261
262
263
264         for(int i = pkg->row1; i < pkg->row2; i++)
265         {
266                 switch(plugin->get_input()->get_color_model())
267                 {
268                         case BC_RGB888:
269                                 PROCESS(unsigned char, 0xff, 3, 0)
270                                 break;
271                         case BC_RGBA8888:
272                                 PROCESS(unsigned char, 0xff, 4, 0)
273                                 break;
274                         case BC_YUV888:
275                                 PROCESS(unsigned char, 0xff, 3, 1)
276                                 break;
277                         case BC_YUVA8888:
278                                 PROCESS(unsigned char, 0xff, 4, 1)
279                                 break;
280                         case BC_RGB_FLOAT:
281                                 PROCESS(float, 1.0, 3, 0)
282                                 break;
283                         case BC_RGBA_FLOAT:
284                                 PROCESS(float, 1.0, 4, 0)
285                                 break;
286                 }
287         }
288 }
289
290
291
292
293
294
295 Color3WayEngine::Color3WayEngine(Color3WayMain *plugin, int cpus)
296  : LoadServer(cpus, cpus)
297 {
298         this->plugin = plugin;
299 }
300
301 Color3WayEngine::~Color3WayEngine()
302 {
303 }
304
305 void Color3WayEngine::init_packages()
306 {
307
308 #if 0
309 printf("Color3WayEngine::init_packages %d\n", __LINE__);
310 for(int i = 0; i <= 255; i++)
311 {
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));
316 }
317 #endif
318
319         for(int i = 0; i < LoadServer::get_total_packages(); i++)
320         {
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();
324         }
325 }
326
327
328 LoadClient* Color3WayEngine::new_client()
329 {
330         return new Color3WayUnit(plugin, this);
331 }
332
333 LoadPackage* Color3WayEngine::new_package()
334 {
335         return new Color3WayPackage;
336 }
337
338
339
340
341
342
343
344
345
346
347 Color3WayMain::Color3WayMain(PluginServer *server)
348  : PluginVClient(server)
349 {
350         need_reconfigure = 1;
351         engine = 0;
352         w = 500;
353         h = 300;
354         for(int i = 0; i < SECTIONS; i++) copy_to_all[i] = 0;
355 }
356
357 Color3WayMain::~Color3WayMain()
358 {
359
360         delete engine;
361 }
362
363 const char* Color3WayMain::plugin_title() { return N_("Color 3 Way"); }
364 int Color3WayMain::is_realtime() { return 1; }
365
366
367 int Color3WayMain::reconfigure()
368 {
369
370         return 0;
371 }
372
373 void Color3WayMain::process_pixel(float *r,
374         float *g,
375         float *b,
376         float r_in,
377         float g_in,
378         float b_in,
379         float x,
380         float y)
381 {
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++)
388         {
389                 calculate_factors(r_factor + i,
390                         g_factor + i,
391                         b_factor + i,
392                         x,
393                         y);
394                 CALCULATE_FACTORS(s_factor[i], v_factor[i], 0, 0)
395         }
396
397         PROCESS_PIXEL(r_in, g_in, b_in);
398         *r = r_in;
399         *g = g_in;
400         *b = b_in;
401 }
402
403 void Color3WayMain::calculate_factors(float *r,
404         float *g,
405         float *b,
406         float x,
407         float y)
408 {
409 //      float h = atan2(-x, -y) * 360 / 2 / M_PI + 180;
410 //      float v = 1.0;
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);
414
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));
418
419         *r = 1.0 - *r;
420         *g = 1.0 - *g;
421         *b = 1.0 - *b;
422 }
423
424 void Color3WayMain::calculate_factors(float *r, float *g, float *b, int section)
425 {
426         calculate_factors(r, g, b, config.hue_x[section], config.hue_y[section]);
427
428
429 //printf("Color3WayMain::calculate_factors %d %f %f %f\n", __LINE__, *r, *g, *b);
430 }
431
432
433
434
435
436
437
438 LOAD_CONFIGURATION_MACRO(Color3WayMain, Color3WayConfig)
439 NEW_WINDOW_MACRO(Color3WayMain, Color3WayWindow)
440
441
442
443
444
445 int Color3WayMain::process_buffer(VFrame *frame,
446         int64_t start_position,
447         double frame_rate)
448 {
449         need_reconfigure |= load_configuration();
450
451         if(!engine) engine = new Color3WayEngine(this,
452 //              1);
453                 PluginClient::smp + 1);
454
455 //printf("Color3WayMain::process_realtime 1 %d\n", need_reconfigure);
456         if(need_reconfigure)
457         {
458
459                 reconfigure();
460                 need_reconfigure = 0;
461         }
462
463
464
465         read_frame(frame,
466                 0,
467                 get_source_position(),
468                 get_framerate(),
469                 get_use_opengl());
470
471         int aggregate_interpolate = 0;
472         int aggregate_gamma = 0;
473         get_aggregation(&aggregate_interpolate,
474                 &aggregate_gamma);
475
476         engine->process_packages();
477
478         return 0;
479 }
480
481
482 void Color3WayMain::update_gui()
483 {
484         if(thread)
485         {
486                 load_configuration();
487                 ((Color3WayWindow*)thread->window)->lock_window("Color3WayMain::update_gui");
488                 ((Color3WayWindow*)thread->window)->update();
489                 ((Color3WayWindow*)thread->window)->unlock_window();
490         }
491 }
492
493
494
495
496 void Color3WayMain::save_data(KeyFrame *keyframe)
497 {
498         FileXML output;
499
500 // cause data to be stored directly in text
501         output.set_shared_output(keyframe->xbuf);
502         output.tag.set_title("COLOR3WAY");
503         for(int i = 0; i < SECTIONS; i++)
504         {
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]);
514                 if(is_defaults())
515                 {
516                         sprintf(string, "COPY_TO_ALL_%d", i);
517                         output.tag.set_property(string, copy_to_all[i]);
518                 }
519         }
520
521         if(is_defaults())
522         {
523                 output.tag.set_property("W",  w);
524                 output.tag.set_property("H",  h);
525         }
526
527         output.append_tag();
528         output.tag.set_title("/COLOR3WAY");
529         output.append_tag();
530         output.append_newline();
531         output.terminate_string();
532 }
533
534 void Color3WayMain::read_data(KeyFrame *keyframe)
535 {
536         FileXML input;
537
538         input.set_shared_input(keyframe->xbuf);
539
540         int result = 0;
541
542         while(!result)
543         {
544                 result = input.read_tag();
545
546                 if(!result)
547                 {
548                         if(input.tag.title_is("COLOR3WAY"))
549                         {
550                                 for(int i = 0; i < SECTIONS; i++)
551                                 {
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]);
561
562                                         if(is_defaults())
563                                         {
564                                                 sprintf(string, "COPY_TO_ALL_%d", i);
565                                                 copy_to_all[i] = input.tag.get_property(string, copy_to_all[i]);
566                                         }
567                                 }
568
569                                 if(is_defaults())
570                                 {
571                                         w = input.tag.get_property("W", w);
572                                         h = input.tag.get_property("H", h);
573                                 }
574                         }
575                 }
576         }
577 }
578
579 void Color3WayMain::get_aggregation(int *aggregate_interpolate,
580         int *aggregate_gamma)
581 {
582         if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
583                 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
584         {
585                 *aggregate_interpolate = 1;
586                 *aggregate_gamma = 1;
587         }
588         else
589         if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
590         {
591                 *aggregate_interpolate = 1;
592         }
593         else
594         if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
595         {
596                 *aggregate_gamma = 1;
597         }
598 }
599
600