r864: Merge 2.1:
[cinelerra_cv/ct.git] / plugins / huesaturation / huesaturation.C
blobc0a1d27517054334fd9aa6c6fb8ebf19512baa91
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "language.h"
7 #include "loadbalance.h"
8 #include "picon_png.h"
9 #include "plugincolors.h"
10 #include "pluginvclient.h"
11 #include "vframe.h"
13 #include <stdint.h>
14 #include <string.h>
17 class HueEffect;
19 #define MINHUE -180
20 #define MAXHUE 180
21 #define MINSATURATION -100
22 #define MAXSATURATION 100
23 #define MINVALUE -100
24 #define MAXVALUE 100
31 class HueConfig
33 public:
34         HueConfig();
35         
36         void copy_from(HueConfig &src);
37         int equivalent(HueConfig &src);
38         void interpolate(HueConfig &prev, 
39                 HueConfig &next, 
40                 long prev_frame, 
41                 long next_frame, 
42                 long current_frame);
43         float hue, saturation, value;
46 class HueSlider : public BC_FSlider
48 public:
49         HueSlider(HueEffect *plugin, int x, int y, int w);
50         int handle_event();
51         HueEffect *plugin;
54 class SaturationSlider : public BC_FSlider
56 public:
57         SaturationSlider(HueEffect *plugin, int x, int y, int w);
58         int handle_event();
59         char* get_caption();
60         HueEffect *plugin;
61         char string[BCTEXTLEN];
64 class ValueSlider : public BC_FSlider
66 public:
67         ValueSlider(HueEffect *plugin, int x, int y, int w);
68         int handle_event();
69         char* get_caption();
70         HueEffect *plugin;
71         char string[BCTEXTLEN];
74 class HueWindow : public BC_Window
76 public:
77         HueWindow(HueEffect *plugin, int x, int y);
78         void create_objects();
79         int close_event();
80         HueEffect *plugin;
81         HueSlider *hue;
82         SaturationSlider *saturation;
83         ValueSlider *value;
86 PLUGIN_THREAD_HEADER(HueEffect, HueThread, HueWindow)
88 class HueEngine : public LoadServer
90 public:
91         HueEngine(HueEffect *plugin, int cpus);
92         void init_packages();
93         LoadClient* new_client();
94         LoadPackage* new_package();
95         HueEffect *plugin;
98 class HuePackage : public LoadPackage
100 public:
101         HuePackage();
102         int row1, row2;
105 class HueUnit : public LoadClient
107 public:
108         HueUnit(HueEffect *plugin, HueEngine *server);
109         void process_package(LoadPackage *package);
110         HueEffect *plugin;
111         YUV yuv;
114 class HueEffect : public PluginVClient
116 public:
117         HueEffect(PluginServer *server);
118         ~HueEffect();
119         
120         int process_buffer(VFrame *frame,
121                 int64_t start_position,
122                 double frame_rate);
123         int is_realtime();
124         char* plugin_title();
125         VFrame* new_picon();
126         int load_configuration();
127         int load_defaults();
128         int save_defaults();
129         void save_data(KeyFrame *keyframe);
130         void read_data(KeyFrame *keyframe);
131         int show_gui();
132         int set_string();
133         void raise_window();
134         void update_gui();
135         
136         HueConfig config;
137         VFrame *input, *output;
138         BC_Hash *defaults;
139         HueThread *thread;
140         HueEngine *engine;
162 HueConfig::HueConfig()
164         hue = saturation = value = 0;
166         
167 void HueConfig::copy_from(HueConfig &src)
169         hue = src.hue;
170         saturation = src.saturation;
171         value = src.value;
173 int HueConfig::equivalent(HueConfig &src)
175         return EQUIV(hue, src.hue) && 
176                 EQUIV(saturation, src.saturation) && 
177                 EQUIV(value, src.value);
179 void HueConfig::interpolate(HueConfig &prev, 
180         HueConfig &next, 
181         long prev_frame, 
182         long next_frame, 
183         long current_frame)
185         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
186         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
188         this->hue = prev.hue * prev_scale + next.hue * next_scale;
189         this->saturation = prev.saturation * prev_scale + next.saturation * next_scale;
190         this->value = prev.value * prev_scale + next.value * next_scale;
200 HueSlider::HueSlider(HueEffect *plugin, int x, int y, int w)
201  : BC_FSlider(x, 
202                         y,
203                         0,
204                         w, 
205                         w, 
206                         (float)MINHUE, 
207                         (float)MAXHUE, 
208                         plugin->config.hue)
210         this->plugin = plugin;
212 int HueSlider::handle_event()
214         plugin->config.hue = get_value();
215         plugin->send_configure_change();
216         return 1;
225 SaturationSlider::SaturationSlider(HueEffect *plugin, int x, int y, int w)
226  : BC_FSlider(x, 
227                         y,
228                         0,
229                         w, 
230                         w, 
231                         (float)MINSATURATION, 
232                         (float)MAXSATURATION, 
233                         plugin->config.saturation)
235         this->plugin = plugin;
237 int SaturationSlider::handle_event()
239         plugin->config.saturation = get_value();
240         plugin->send_configure_change();
241         return 1;
244 char* SaturationSlider::get_caption()
246         float fraction = ((float)plugin->config.saturation - MINSATURATION) / 
247                 MAXSATURATION;;
248         sprintf(string, "%0.4f", fraction);
249         return string;
258 ValueSlider::ValueSlider(HueEffect *plugin, int x, int y, int w)
259  : BC_FSlider(x, 
260                         y,
261                         0,
262                         w, 
263                         w, 
264                         (float)MINVALUE, 
265                         (float)MAXVALUE, 
266                         plugin->config.value)
268         this->plugin = plugin;
270 int ValueSlider::handle_event()
272         plugin->config.value = get_value();
273         plugin->send_configure_change();
274         return 1;
277 char* ValueSlider::get_caption()
279         float fraction = ((float)plugin->config.value - MINVALUE) / MAXVALUE;
280         sprintf(string, "%0.4f", fraction);
281         return string;
290 HueWindow::HueWindow(HueEffect *plugin, int x, int y)
291  : BC_Window(plugin->gui_string, 
292                         x,
293                         y,
294                         310, 
295                         100, 
296                         310, 
297                         100, 
298                         0,
299                         0, 
300                         1)
302         this->plugin = plugin;
304 void HueWindow::create_objects()
306         int x = 10, y = 10, x1 = 100;
307         add_subwindow(new BC_Title(x, y, _("Hue:")));
308         add_subwindow(hue = new HueSlider(plugin, x1, y, 200));
309         y += 30;
310         add_subwindow(new BC_Title(x, y, _("Saturation:")));
311         add_subwindow(saturation = new SaturationSlider(plugin, x1, y, 200));
312         y += 30;
313         add_subwindow(new BC_Title(x, y, _("Value:")));
314         add_subwindow(value = new ValueSlider(plugin, x1, y, 200));
315         show_window();
316         flush();
320 WINDOW_CLOSE_EVENT(HueWindow)
329 PLUGIN_THREAD_OBJECT(HueEffect, HueThread, HueWindow)
331 HueEngine::HueEngine(HueEffect *plugin, int cpus)
332  : LoadServer(cpus, cpus)
334         this->plugin = plugin;
336 void HueEngine::init_packages()
338         for(int i = 0; i < LoadServer::get_total_packages(); i++)
339         {
340                 HuePackage *pkg = (HuePackage*)get_package(i);
341                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
342                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
343         }
345 LoadClient* HueEngine::new_client()
347         return new HueUnit(plugin, this);
349 LoadPackage* HueEngine::new_package()
351         return new HuePackage;
361 HuePackage::HuePackage()
362  : LoadPackage()
366 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
367  : LoadClient(server)
369         this->plugin = plugin;
378 #define HUESATURATION(type, max, components, use_yuv) \
379 { \
380         float h_offset = plugin->config.hue; \
381         float s_offset = ((float)plugin->config.saturation - MINSATURATION) / MAXSATURATION; \
382         float v_offset = ((float)plugin->config.value - MINVALUE) / MAXVALUE; \
383         for(int i = pkg->row1; i < pkg->row2; i++) \
384         { \
385                 type* in_row = (type*)plugin->input->get_rows()[i]; \
386                 type* out_row = (type*)plugin->output->get_rows()[i]; \
388                 for(int j = 0; j < w; j++) \
389                 { \
390                         float h, s, va; \
391                         int y, u, v; \
392                         float r, g, b; \
393                         int r_i, g_i, b_i; \
395                         if(use_yuv) \
396                         { \
397                                 y = (int)in_row[0]; \
398                                 u = (int)in_row[1]; \
399                                 v = (int)in_row[2]; \
400                                 if(max == 0xffff) \
401                                         yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
402                                 else \
403                                         yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
404                                 HSV::rgb_to_hsv((float)r_i / max, \
405                                         (float)g_i / max, \
406                                         (float)b_i / max, \
407                                         h, \
408                                         s, \
409                                         va); \
410                         } \
411                         else \
412                         { \
413                                 r = (float)in_row[0] / max; \
414                                 g = (float)in_row[1] / max; \
415                                 b = (float)in_row[2] / max; \
416                                 HSV::rgb_to_hsv(r, g, b, h, s, va); \
417                         } \
420                         h += h_offset; \
421                         s *= s_offset; \
422                         va *= v_offset; \
424                         if(h >= 360) h -= 360; \
425                         if(h < 0) h += 360; \
426                         if(sizeof(type) < 4) \
427                         { \
428                                 if(s > 1) s = 1; \
429                                 if(va > 1) va = 1; \
430                                 if(s < 0) s = 0; \
431                                 if(va < 0) va = 0; \
432                         } \
434                         if(use_yuv) \
435                         { \
436                                 HSV::hsv_to_yuv(y, u, v, h, s, va, max); \
437                                 out_row[0] = y; \
438                                 out_row[1] = u; \
439                                 out_row[2] = v; \
440                         } \
441                         else \
442                         { \
443                                 HSV::hsv_to_rgb(r, g, b, h, s, va); \
444                                 if(sizeof(type) < 4) \
445                                 { \
446                                         r *= max; \
447                                         g *= max; \
448                                         b *= max; \
449                                         out_row[0] = (type)CLIP(r, 0, max); \
450                                         out_row[1] = (type)CLIP(g, 0, max); \
451                                         out_row[2] = (type)CLIP(b, 0, max); \
452                                 } \
453                                 else \
454                                 { \
455                                         out_row[0] = (type)r; \
456                                         out_row[1] = (type)g; \
457                                         out_row[2] = (type)b; \
458                                 } \
459                         } \
461                         in_row += components; \
462                         out_row += components; \
463                 } \
464         } \
468 void HueUnit::process_package(LoadPackage *package)
470         HuePackage *pkg = (HuePackage*)package;
471         int w = plugin->input->get_w();
473         switch(plugin->input->get_color_model())
474         {
475                 case BC_RGB888:
476                         HUESATURATION(unsigned char, 0xff, 3, 0)
477                         break;
479                 case BC_RGB_FLOAT:
480                         HUESATURATION(float, 1, 3, 0)
481                         break;
483                 case BC_YUV888:
484                         HUESATURATION(unsigned char, 0xff, 3, 1)
485                         break;
487                 case BC_RGB161616:
488                         HUESATURATION(uint16_t, 0xffff, 3, 0)
489                         break;
491                 case BC_YUV161616:
492                         HUESATURATION(uint16_t, 0xffff, 3, 1)
493                         break;
495                 case BC_RGBA_FLOAT:
496                         HUESATURATION(float, 1, 4, 0)
497                         break;
499                 case BC_RGBA8888:
500                         HUESATURATION(unsigned char, 0xff, 4, 0)
501                         break;
503                 case BC_YUVA8888:
504                         HUESATURATION(unsigned char, 0xff, 4, 1)
505                         break;
507                 case BC_RGBA16161616:
508                         HUESATURATION(uint16_t, 0xffff, 4, 0)
509                         break;
511                 case BC_YUVA16161616:
512                         HUESATURATION(uint16_t, 0xffff, 4, 1)
513                         break;
515         }
521 REGISTER_PLUGIN(HueEffect)
524 HueEffect::HueEffect(PluginServer *server)
525  : PluginVClient(server)
527         engine = 0;
528         PLUGIN_CONSTRUCTOR_MACRO
530 HueEffect::~HueEffect()
532         PLUGIN_DESTRUCTOR_MACRO
533         if(engine) delete engine;
536 int HueEffect::process_buffer(VFrame *frame,
537         int64_t start_position,
538         double frame_rate)
540         load_configuration();
542         read_frame(frame, 
543                 0, 
544                 start_position, 
545                 frame_rate);
546         
548         this->input = frame;
549         this->output = frame;
550         if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
551         {
552                 return 0;
553         }
554         else
555         {
556                 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
557                 
558                 engine->process_packages();
559         }
560         return 0;
563 char* HueEffect::plugin_title() { return N_("Hue saturation"); }
564 int HueEffect::is_realtime() { return 1; }
566 NEW_PICON_MACRO(HueEffect)
567 SHOW_GUI_MACRO(HueEffect, HueThread)
568 SET_STRING_MACRO(HueEffect)
569 RAISE_WINDOW_MACRO(HueEffect)
570 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
572 int HueEffect::load_defaults()
574         char directory[BCTEXTLEN];
575         sprintf(directory, "%shuesaturation.rc", BCASTDIR);
576         defaults = new BC_Hash(directory);
577         defaults->load();
578         config.hue = defaults->get("HUE", config.hue);
579         config.saturation = defaults->get("SATURATION", config.saturation);
580         config.value = defaults->get("VALUE", config.value);
581         return 0;
583 int HueEffect::save_defaults()
585         defaults->update("HUE", config.hue);
586         defaults->update("SATURATION", config.saturation);
587         defaults->update("VALUE", config.value);
588         defaults->save();
589         return 0;
591 void HueEffect::save_data(KeyFrame *keyframe)
593         FileXML output;
594         output.set_shared_string(keyframe->data, MESSAGESIZE);
595         output.tag.set_title("HUESATURATION");
596         output.tag.set_property("HUE", config.hue);
597         output.tag.set_property("SATURATION", config.saturation);
598         output.tag.set_property("VALUE", config.value);
599         output.append_tag();
600         output.terminate_string();
602 void HueEffect::read_data(KeyFrame *keyframe)
604         FileXML input;
605         input.set_shared_string(keyframe->data, strlen(keyframe->data));
606         while(!input.read_tag())
607         {
608                 if(input.tag.title_is("HUESATURATION"))
609                 {
610                         config.hue = input.tag.get_property("HUE", config.hue);
611                         config.saturation = input.tag.get_property("SATURATION", config.saturation);
612                         config.value = input.tag.get_property("VALUE", config.value);
613                 }
614         }
616 void HueEffect::update_gui()
618         if(thread)
619         {
620                 thread->window->lock_window();
621                 load_configuration();
622                 thread->window->hue->update(config.hue);
623                 thread->window->saturation->update(config.saturation);
624                 thread->window->value->update(config.value);
625                 thread->window->unlock_window();
626         }