r860: Merge 2.1:
[cinelerra_cv.git] / plugins / huesaturation / huesaturation.C
blob5169c9300b98b90bd2f29e11ecf2360bb45b2fb8
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         HueEffect *plugin;
62 class ValueSlider : public BC_FSlider
64 public:
65         ValueSlider(HueEffect *plugin, int x, int y, int w);
66         int handle_event();
67         HueEffect *plugin;
70 class HueWindow : public BC_Window
72 public:
73         HueWindow(HueEffect *plugin, int x, int y);
74         void create_objects();
75         int close_event();
76         HueEffect *plugin;
77         HueSlider *hue;
78         SaturationSlider *saturation;
79         ValueSlider *value;
82 PLUGIN_THREAD_HEADER(HueEffect, HueThread, HueWindow)
84 class HueEngine : public LoadServer
86 public:
87         HueEngine(HueEffect *plugin, int cpus);
88         void init_packages();
89         LoadClient* new_client();
90         LoadPackage* new_package();
91         HueEffect *plugin;
94 class HuePackage : public LoadPackage
96 public:
97         HuePackage();
98         int row1, row2;
101 class HueUnit : public LoadClient
103 public:
104         HueUnit(HueEffect *plugin, HueEngine *server);
105         void process_package(LoadPackage *package);
106         HueEffect *plugin;
107         YUV yuv;
110 class HueEffect : public PluginVClient
112 public:
113         HueEffect(PluginServer *server);
114         ~HueEffect();
115         
116         int process_realtime(VFrame *input, VFrame *output);
117         int is_realtime();
118         char* plugin_title();
119         VFrame* new_picon();
120         int load_configuration();
121         int load_defaults();
122         int save_defaults();
123         void save_data(KeyFrame *keyframe);
124         void read_data(KeyFrame *keyframe);
125         int show_gui();
126         int set_string();
127         void raise_window();
128         void update_gui();
129         
130         HueConfig config;
131         VFrame *input, *output;
132         BC_Hash *defaults;
133         HueThread *thread;
134         HueEngine *engine;
156 HueConfig::HueConfig()
158         hue = saturation = value = 0;
160         
161 void HueConfig::copy_from(HueConfig &src)
163         hue = src.hue;
164         saturation = src.saturation;
165         value = src.value;
167 int HueConfig::equivalent(HueConfig &src)
169         return EQUIV(hue, src.hue) && 
170                 EQUIV(saturation, src.saturation) && 
171                 EQUIV(value, src.value);
173 void HueConfig::interpolate(HueConfig &prev, 
174         HueConfig &next, 
175         long prev_frame, 
176         long next_frame, 
177         long current_frame)
179         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
180         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
182         this->hue = prev.hue * prev_scale + next.hue * next_scale;
183         this->saturation = prev.saturation * prev_scale + next.saturation * next_scale;
184         this->value = prev.value * prev_scale + next.value * next_scale;
194 HueSlider::HueSlider(HueEffect *plugin, int x, int y, int w)
195  : BC_FSlider(x, 
196                         y,
197                         0,
198                         w, 
199                         w, 
200                         (float)MINHUE, 
201                         (float)MAXHUE, 
202                         plugin->config.hue)
204         this->plugin = plugin;
206 int HueSlider::handle_event()
208         plugin->config.hue = get_value();
209         plugin->send_configure_change();
210         return 1;
219 SaturationSlider::SaturationSlider(HueEffect *plugin, int x, int y, int w)
220  : BC_FSlider(x, 
221                         y,
222                         0,
223                         w, 
224                         w, 
225                         (float)MINSATURATION, 
226                         (float)MAXSATURATION, 
227                         plugin->config.saturation)
229         this->plugin = plugin;
231 int SaturationSlider::handle_event()
233         plugin->config.saturation = get_value();
234         plugin->send_configure_change();
235         return 1;
244 ValueSlider::ValueSlider(HueEffect *plugin, int x, int y, int w)
245  : BC_FSlider(x, 
246                         y,
247                         0,
248                         w, 
249                         w, 
250                         (float)MINVALUE, 
251                         (float)MAXVALUE, 
252                         plugin->config.value)
254         this->plugin = plugin;
256 int ValueSlider::handle_event()
258         plugin->config.value = get_value();
259         plugin->send_configure_change();
260         return 1;
270 HueWindow::HueWindow(HueEffect *plugin, int x, int y)
271  : BC_Window(plugin->gui_string, 
272                         x,
273                         y,
274                         310, 
275                         100, 
276                         310, 
277                         100, 
278                         0,
279                         0, 
280                         1)
282         this->plugin = plugin;
284 void HueWindow::create_objects()
286         int x = 10, y = 10, x1 = 100;
287         add_subwindow(new BC_Title(x, y, _("Hue:")));
288         add_subwindow(hue = new HueSlider(plugin, x1, y, 200));
289         y += 30;
290         add_subwindow(new BC_Title(x, y, _("Saturation:")));
291         add_subwindow(saturation = new SaturationSlider(plugin, x1, y, 200));
292         y += 30;
293         add_subwindow(new BC_Title(x, y, _("Value:")));
294         add_subwindow(value = new ValueSlider(plugin, x1, y, 200));
295         show_window();
296         flush();
300 WINDOW_CLOSE_EVENT(HueWindow)
309 PLUGIN_THREAD_OBJECT(HueEffect, HueThread, HueWindow)
311 HueEngine::HueEngine(HueEffect *plugin, int cpus)
312  : LoadServer(cpus, cpus)
314         this->plugin = plugin;
316 void HueEngine::init_packages()
318         for(int i = 0; i < LoadServer::get_total_packages(); i++)
319         {
320                 HuePackage *pkg = (HuePackage*)get_package(i);
321                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
322                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
323         }
325 LoadClient* HueEngine::new_client()
327         return new HueUnit(plugin, this);
329 LoadPackage* HueEngine::new_package()
331         return new HuePackage;
341 HuePackage::HuePackage()
342  : LoadPackage()
346 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
347  : LoadClient(server)
349         this->plugin = plugin;
358 #define HUESATURATION(type, max, components, use_yuv) \
359 { \
360         float h_offset = plugin->config.hue; \
361         float s_offset = ((float)plugin->config.saturation - MINSATURATION) / MAXSATURATION; \
362         float v_offset = ((float)plugin->config.value - MINVALUE) / MAXVALUE; \
363         for(int i = pkg->row1; i < pkg->row2; i++) \
364         { \
365                 type* in_row = (type*)plugin->input->get_rows()[i]; \
366                 type* out_row = (type*)plugin->output->get_rows()[i]; \
368                 for(int j = 0; j < w; j++) \
369                 { \
370                         float h, s, va; \
371                         int y, u, v; \
372                         float r, g, b; \
373                         int r_i, g_i, b_i; \
375                         if(use_yuv) \
376                         { \
377                                 y = (int)in_row[0]; \
378                                 u = (int)in_row[1]; \
379                                 v = (int)in_row[2]; \
380                                 if(max == 0xffff) \
381                                         yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
382                                 else \
383                                         yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
384                                 HSV::rgb_to_hsv((float)r_i / max, \
385                                         (float)g_i / max, \
386                                         (float)b_i / max, \
387                                         h, \
388                                         s, \
389                                         va); \
390                         } \
391                         else \
392                         { \
393                                 r = (float)in_row[0] / max; \
394                                 g = (float)in_row[1] / max; \
395                                 b = (float)in_row[2] / max; \
396                                 HSV::rgb_to_hsv(r, g, b, h, s, va); \
397                         } \
400                         h += h_offset; \
401                         s *= s_offset; \
402                         va *= v_offset; \
404                         if(h >= 360) h -= 360; \
405                         if(h < 0) h += 360; \
406                         if(sizeof(type) < 4) \
407                         { \
408                                 if(s > 1) s = 1; \
409                                 if(va > 1) va = 1; \
410                                 if(s < 0) s = 0; \
411                                 if(va < 0) va = 0; \
412                         } \
414                         if(use_yuv) \
415                         { \
416                                 HSV::hsv_to_yuv(y, u, v, h, s, va, max); \
417                                 out_row[0] = y; \
418                                 out_row[1] = u; \
419                                 out_row[2] = v; \
420                         } \
421                         else \
422                         { \
423                                 HSV::hsv_to_rgb(r, g, b, h, s, va); \
424                                 if(sizeof(type) < 4) \
425                                 { \
426                                         r *= max; \
427                                         g *= max; \
428                                         b *= max; \
429                                         out_row[0] = (type)CLIP(r, 0, max); \
430                                         out_row[1] = (type)CLIP(g, 0, max); \
431                                         out_row[2] = (type)CLIP(b, 0, max); \
432                                 } \
433                                 else \
434                                 { \
435                                         out_row[0] = (type)r; \
436                                         out_row[1] = (type)g; \
437                                         out_row[2] = (type)b; \
438                                 } \
439                         } \
441                         in_row += components; \
442                         out_row += components; \
443                 } \
444         } \
448 void HueUnit::process_package(LoadPackage *package)
450         HuePackage *pkg = (HuePackage*)package;
451         int w = plugin->input->get_w();
453         switch(plugin->input->get_color_model())
454         {
455                 case BC_RGB888:
456                         HUESATURATION(unsigned char, 0xff, 3, 0)
457                         break;
459                 case BC_RGB_FLOAT:
460                         HUESATURATION(float, 1, 3, 0)
461                         break;
463                 case BC_YUV888:
464                         HUESATURATION(unsigned char, 0xff, 3, 1)
465                         break;
467                 case BC_RGB161616:
468                         HUESATURATION(uint16_t, 0xffff, 3, 0)
469                         break;
471                 case BC_YUV161616:
472                         HUESATURATION(uint16_t, 0xffff, 3, 1)
473                         break;
475                 case BC_RGBA_FLOAT:
476                         HUESATURATION(float, 1, 4, 0)
477                         break;
479                 case BC_RGBA8888:
480                         HUESATURATION(unsigned char, 0xff, 4, 0)
481                         break;
483                 case BC_YUVA8888:
484                         HUESATURATION(unsigned char, 0xff, 4, 1)
485                         break;
487                 case BC_RGBA16161616:
488                         HUESATURATION(uint16_t, 0xffff, 4, 0)
489                         break;
491                 case BC_YUVA16161616:
492                         HUESATURATION(uint16_t, 0xffff, 4, 1)
493                         break;
495         }
501 REGISTER_PLUGIN(HueEffect)
504 HueEffect::HueEffect(PluginServer *server)
505  : PluginVClient(server)
507         engine = 0;
508         PLUGIN_CONSTRUCTOR_MACRO
510 HueEffect::~HueEffect()
512         PLUGIN_DESTRUCTOR_MACRO
513         if(engine) delete engine;
516 int HueEffect::process_realtime(VFrame *input, VFrame *output)
518         load_configuration();
519         this->input = input;
520         this->output = output;
521         if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
522         {
523                 if(input->get_rows()[0] != output->get_rows()[0])
524                         output->copy_from(input);
525         }
526         else
527         {
528                 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
529                 
530                 engine->process_packages();
531         }
532         return 0;
535 char* HueEffect::plugin_title() { return N_("Hue saturation"); }
536 int HueEffect::is_realtime() { return 1; }
538 NEW_PICON_MACRO(HueEffect)
539 SHOW_GUI_MACRO(HueEffect, HueThread)
540 SET_STRING_MACRO(HueEffect)
541 RAISE_WINDOW_MACRO(HueEffect)
542 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
544 int HueEffect::load_defaults()
546         char directory[BCTEXTLEN];
547         sprintf(directory, "%shuesaturation.rc", BCASTDIR);
548         defaults = new BC_Hash(directory);
549         defaults->load();
550         config.hue = defaults->get("HUE", config.hue);
551         config.saturation = defaults->get("SATURATION", config.saturation);
552         config.value = defaults->get("VALUE", config.value);
553         return 0;
555 int HueEffect::save_defaults()
557         defaults->update("HUE", config.hue);
558         defaults->update("SATURATION", config.saturation);
559         defaults->update("VALUE", config.value);
560         defaults->save();
561         return 0;
563 void HueEffect::save_data(KeyFrame *keyframe)
565         FileXML output;
566         output.set_shared_string(keyframe->data, MESSAGESIZE);
567         output.tag.set_title("HUESATURATION");
568         output.tag.set_property("HUE", config.hue);
569         output.tag.set_property("SATURATION", config.saturation);
570         output.tag.set_property("VALUE", config.value);
571         output.append_tag();
572         output.terminate_string();
574 void HueEffect::read_data(KeyFrame *keyframe)
576         FileXML input;
577         input.set_shared_string(keyframe->data, strlen(keyframe->data));
578         while(!input.read_tag())
579         {
580                 if(input.tag.title_is("HUESATURATION"))
581                 {
582                         config.hue = input.tag.get_property("HUE", config.hue);
583                         config.saturation = input.tag.get_property("SATURATION", config.saturation);
584                         config.value = input.tag.get_property("VALUE", config.value);
585                 }
586         }
588 void HueEffect::update_gui()
590         if(thread)
591         {
592                 thread->window->lock_window();
593                 load_configuration();
594                 thread->window->hue->update(config.hue);
595                 thread->window->saturation->update(config.saturation);
596                 thread->window->value->update(config.value);
597                 thread->window->unlock_window();
598         }