r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / huesaturation / huesaturation.C
blob59463e1b89812350806bd0bf1ab6e239688705f1
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "loadbalance.h"
7 #include "picon_png.h"
8 #include "plugincolors.h"
9 #include "pluginvclient.h"
10 #include "vframe.h"
12 #include <stdint.h>
13 #include <string.h>
15 #include <libintl.h>
16 #define _(String) gettext(String)
17 #define gettext_noop(String) String
18 #define N_(String) gettext_noop (String)
20 class HueEffect;
22 #define MINHUE -180
23 #define MAXHUE 180
24 #define MINSATURATION -100
25 #define MAXSATURATION 100
26 #define MINVALUE -100
27 #define MAXVALUE 100
34 class HueConfig
36 public:
37         HueConfig();
38         
39         void copy_from(HueConfig &src);
40         int equivalent(HueConfig &src);
41         void interpolate(HueConfig &prev, 
42                 HueConfig &next, 
43                 long prev_frame, 
44                 long next_frame, 
45                 long current_frame);
46         float hue, saturation, value;
49 class HueSlider : public BC_FSlider
51 public:
52         HueSlider(HueEffect *plugin, int x, int y, int w);
53         int handle_event();
54         HueEffect *plugin;
57 class SaturationSlider : public BC_FSlider
59 public:
60         SaturationSlider(HueEffect *plugin, int x, int y, int w);
61         int handle_event();
62         HueEffect *plugin;
65 class ValueSlider : public BC_FSlider
67 public:
68         ValueSlider(HueEffect *plugin, int x, int y, int w);
69         int handle_event();
70         HueEffect *plugin;
73 class HueWindow : public BC_Window
75 public:
76         HueWindow(HueEffect *plugin, int x, int y);
77         void create_objects();
78         int close_event();
79         HueEffect *plugin;
80         HueSlider *hue;
81         SaturationSlider *saturation;
82         ValueSlider *value;
85 PLUGIN_THREAD_HEADER(HueEffect, HueThread, HueWindow)
87 class HueEngine : public LoadServer
89 public:
90         HueEngine(HueEffect *plugin, int cpus);
91         void init_packages();
92         LoadClient* new_client();
93         LoadPackage* new_package();
94         HueEffect *plugin;
97 class HuePackage : public LoadPackage
99 public:
100         HuePackage();
101         int row1, row2;
104 class HueUnit : public LoadClient
106 public:
107         HueUnit(HueEffect *plugin, HueEngine *server);
108         void process_package(LoadPackage *package);
109         HueEffect *plugin;
110         YUV yuv;
113 class HueEffect : public PluginVClient
115 public:
116         HueEffect(PluginServer *server);
117         ~HueEffect();
118         
119         int process_realtime(VFrame *input, VFrame *output);
120         int is_realtime();
121         char* plugin_title();
122         VFrame* new_picon();
123         int load_configuration();
124         int load_defaults();
125         int save_defaults();
126         void save_data(KeyFrame *keyframe);
127         void read_data(KeyFrame *keyframe);
128         int show_gui();
129         int set_string();
130         void raise_window();
131         void update_gui();
132         
133         HueConfig config;
134         VFrame *input, *output;
135         Defaults *defaults;
136         HueThread *thread;
137         HueEngine *engine;
159 HueConfig::HueConfig()
161         hue = saturation = value = 0;
163         
164 void HueConfig::copy_from(HueConfig &src)
166         hue = src.hue;
167         saturation = src.saturation;
168         value = src.value;
170 int HueConfig::equivalent(HueConfig &src)
172         return EQUIV(hue, src.hue) && 
173                 EQUIV(saturation, src.saturation) && 
174                 EQUIV(value, src.value);
176 void HueConfig::interpolate(HueConfig &prev, 
177         HueConfig &next, 
178         long prev_frame, 
179         long next_frame, 
180         long current_frame)
182         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
183         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
185         this->hue = prev.hue * prev_scale + next.hue * next_scale;
186         this->saturation = prev.saturation * prev_scale + next.saturation * next_scale;
187         this->value = prev.value * prev_scale + next.value * next_scale;
197 HueSlider::HueSlider(HueEffect *plugin, int x, int y, int w)
198  : BC_FSlider(x, 
199                         y,
200                         0,
201                         w, 
202                         w, 
203                         (float)MINHUE, 
204                         (float)MAXHUE, 
205                         plugin->config.hue)
207         this->plugin = plugin;
209 int HueSlider::handle_event()
211         plugin->config.hue = get_value();
212         plugin->send_configure_change();
213         return 1;
222 SaturationSlider::SaturationSlider(HueEffect *plugin, int x, int y, int w)
223  : BC_FSlider(x, 
224                         y,
225                         0,
226                         w, 
227                         w, 
228                         (float)MINSATURATION, 
229                         (float)MAXSATURATION, 
230                         plugin->config.saturation)
232         this->plugin = plugin;
234 int SaturationSlider::handle_event()
236         plugin->config.saturation = get_value();
237         plugin->send_configure_change();
238         return 1;
247 ValueSlider::ValueSlider(HueEffect *plugin, int x, int y, int w)
248  : BC_FSlider(x, 
249                         y,
250                         0,
251                         w, 
252                         w, 
253                         (float)MINVALUE, 
254                         (float)MAXVALUE, 
255                         plugin->config.value)
257         this->plugin = plugin;
259 int ValueSlider::handle_event()
261         plugin->config.value = get_value();
262         plugin->send_configure_change();
263         return 1;
273 HueWindow::HueWindow(HueEffect *plugin, int x, int y)
274  : BC_Window(plugin->gui_string, 
275                         x,
276                         y,
277                         310, 
278                         100, 
279                         310, 
280                         100, 
281                         0,
282                         0, 
283                         1)
285         this->plugin = plugin;
287 void HueWindow::create_objects()
289         int x = 10, y = 10, x1 = 100;
290         add_subwindow(new BC_Title(x, y, _("Hue:")));
291         add_subwindow(hue = new HueSlider(plugin, x1, y, 200));
292         y += 30;
293         add_subwindow(new BC_Title(x, y, _("Saturation:")));
294         add_subwindow(saturation = new SaturationSlider(plugin, x1, y, 200));
295         y += 30;
296         add_subwindow(new BC_Title(x, y, _("Value:")));
297         add_subwindow(value = new ValueSlider(plugin, x1, y, 200));
298         show_window();
299         flush();
303 int HueWindow::close_event()
305         set_done(1);
306         return 1;
312 PLUGIN_THREAD_OBJECT(HueEffect, HueThread, HueWindow)
314 HueEngine::HueEngine(HueEffect *plugin, int cpus)
315  : LoadServer(cpus, cpus)
317         this->plugin = plugin;
319 void HueEngine::init_packages()
321         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
322         int y = 0;
323         for(int i = 0; i < LoadServer::total_packages; i++)
324         {
325                 HuePackage *pkg = (HuePackage*)packages[i];
326                 pkg->row1 = y;
327                 pkg->row2 = y + increment;
328                 y += increment;
329                 if(pkg->row2 > plugin->input->get_h())
330                 {
331                         y = pkg->row2 = plugin->input->get_h();
332                 }
333         }
335 LoadClient* HueEngine::new_client()
337         return new HueUnit(plugin, this);
339 LoadPackage* HueEngine::new_package()
341         return new HuePackage;
351 HuePackage::HuePackage()
352  : LoadPackage()
356 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
357  : LoadClient(server)
359         this->plugin = plugin;
368 #define HUESATURATION(type, max, components, use_yuv) \
369 { \
370         float h_offset = plugin->config.hue; \
371         float s_offset = ((float)plugin->config.saturation + -MINSATURATION) / MAXSATURATION; \
372         float v_offset = ((float)plugin->config.value + -MINVALUE) / MAXVALUE; \
373         for(int i = pkg->row1; i < pkg->row2; i++) \
374         { \
375                 type* in_row = (type*)plugin->input->get_rows()[i]; \
376                 type* out_row = (type*)plugin->output->get_rows()[i]; \
378                 for(int j = 0; j < w; j++) \
379                 { \
380                         float h, s, va; \
381                         int y, u, v; \
382                         float r, g, b; \
383                         int r_i, g_i, b_i; \
385                         if(use_yuv) \
386                         { \
387                                 y = in_row[0]; \
388                                 u = in_row[1]; \
389                                 v = in_row[2]; \
390                                 if(max == 0xffff) \
391                                         yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
392                                 else \
393                                         yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
394                                 HSV::rgb_to_hsv((float)r_i / max, \
395                                         (float)g_i / max, \
396                                         (float)b_i / max, \
397                                         h, \
398                                         s, \
399                                         va); \
400                         } \
401                         else \
402                         { \
403                                 r = (float)in_row[0] / max; \
404                                 g = (float)in_row[1] / max; \
405                                 b = (float)in_row[2] / max; \
406                                 HSV::rgb_to_hsv(r, g, b, h, s, va); \
407                         } \
410                         h += h_offset; \
411                         s *= s_offset; \
412                         va *= v_offset; \
414                         if(h >= 360) h -= 360; \
415                         if(s > 1) s = 1; \
416                         if(va > 1) va = 1; \
417                         if(h < 0) h += 360; \
418                         if(s < 0) s = 0; \
419                         if(va < 0) va = 0; \
421                         if(use_yuv) \
422                         { \
423                                 HSV::hsv_to_yuv(y, u, v, h, s, va, max); \
424                                 out_row[0] = y; \
425                                 out_row[1] = u; \
426                                 out_row[2] = v; \
427                         } \
428                         else \
429                         { \
430                                 HSV::hsv_to_rgb(r, g, b, h, s, va); \
431                                 r *= max; \
432                                 g *= max; \
433                                 b *= max; \
434                                 out_row[0] = (int)CLIP(r, 0, max); \
435                                 out_row[1] = (int)CLIP(g, 0, max); \
436                                 out_row[2] = (int)CLIP(b, 0, max); \
437                         } \
440                         if(components == 4) \
441                                 out_row[3] = in_row[3]; \
442                         in_row += components; \
443                         out_row += components; \
444                 } \
445         } \
449 void HueUnit::process_package(LoadPackage *package)
451         HuePackage *pkg = (HuePackage*)package;
452         int w = plugin->input->get_w();
454         switch(plugin->input->get_color_model())
455         {
456                 case BC_RGB888:
457                         HUESATURATION(unsigned char, 0xff, 3, 0)
458                         break;
460                 case BC_YUV888:
461                         HUESATURATION(unsigned char, 0xff, 3, 1)
462                         break;
464                 case BC_RGB161616:
465                         HUESATURATION(uint16_t, 0xffff, 3, 0)
466                         break;
468                 case BC_YUV161616:
469                         HUESATURATION(uint16_t, 0xffff, 3, 1)
470                         break;
472                 case BC_RGBA8888:
473                         HUESATURATION(unsigned char, 0xff, 4, 0)
474                         break;
476                 case BC_YUVA8888:
477                         HUESATURATION(unsigned char, 0xff, 4, 1)
478                         break;
480                 case BC_RGBA16161616:
481                         HUESATURATION(uint16_t, 0xffff, 4, 0)
482                         break;
484                 case BC_YUVA16161616:
485                         HUESATURATION(uint16_t, 0xffff, 4, 1)
486                         break;
488         }
494 REGISTER_PLUGIN(HueEffect)
497 HueEffect::HueEffect(PluginServer *server)
498  : PluginVClient(server)
500         engine = 0;
501         PLUGIN_CONSTRUCTOR_MACRO
503 HueEffect::~HueEffect()
505         PLUGIN_DESTRUCTOR_MACRO
506         if(engine) delete engine;
509 int HueEffect::process_realtime(VFrame *input, VFrame *output)
511         load_configuration();
512         this->input = input;
513         this->output = output;
514         if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
515         {
516                 if(input->get_rows()[0] != output->get_rows()[0])
517                         output->copy_from(input);
518         }
519         else
520         {
521                 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
522                 
523                 engine->process_packages();
524         }
525         return 0;
527 int HueEffect::is_realtime()
529         return 1;
531 char* HueEffect::plugin_title()
533         return _("Hue saturation");
536 NEW_PICON_MACRO(HueEffect)
537 SHOW_GUI_MACRO(HueEffect, HueThread)
538 SET_STRING_MACRO(HueEffect)
539 RAISE_WINDOW_MACRO(HueEffect)
540 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
542 int HueEffect::load_defaults()
544         char directory[BCTEXTLEN];
545         sprintf(directory, "%shuesaturation.rc", BCASTDIR);
546         defaults = new Defaults(directory);
547         defaults->load();
548         config.hue = defaults->get("HUE", config.hue);
549         config.saturation = defaults->get("SATURATION", config.saturation);
550         config.value = defaults->get("VALUE", config.value);
551         return 0;
553 int HueEffect::save_defaults()
555         defaults->update("HUE", config.hue);
556         defaults->update("SATURATION", config.saturation);
557         defaults->update("VALUE", config.value);
558         defaults->save();
559         return 0;
561 void HueEffect::save_data(KeyFrame *keyframe)
563         FileXML output;
564         output.set_shared_string(keyframe->data, MESSAGESIZE);
565         output.tag.set_title("HUESATURATION");
566         output.tag.set_property("HUE", config.hue);
567         output.tag.set_property("SATURATION", config.saturation);
568         output.tag.set_property("VALUE", config.value);
569         output.append_tag();
570         output.terminate_string();
572 void HueEffect::read_data(KeyFrame *keyframe)
574         FileXML input;
575         input.set_shared_string(keyframe->data, strlen(keyframe->data));
576         while(!input.read_tag())
577         {
578                 if(input.tag.title_is("HUESATURATION"))
579                 {
580                         config.hue = input.tag.get_property("HUE", config.hue);
581                         config.saturation = input.tag.get_property("SATURATION", config.saturation);
582                         config.value = input.tag.get_property("VALUE", config.value);
583                 }
584         }
586 void HueEffect::update_gui()
588         if(thread)
589         {
590                 thread->window->lock_window();
591                 load_configuration();
592                 thread->window->hue->update(config.hue);
593                 thread->window->saturation->update(config.saturation);
594                 thread->window->value->update(config.value);
595                 thread->window->unlock_window();
596         }