r499: This commit was manufactured by cvs2svn to create tag 'r1_2_1-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / huesaturation / huesaturation.C
blobbf8abb8028823c6ff4b1686c9dafa3d174ff9f2d
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.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         Defaults *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         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
319         int y = 0;
320         for(int i = 0; i < LoadServer::total_packages; i++)
321         {
322                 HuePackage *pkg = (HuePackage*)packages[i];
323                 pkg->row1 = y;
324                 pkg->row2 = y + increment;
325                 y += increment;
326                 if(pkg->row2 > plugin->input->get_h())
327                 {
328                         y = pkg->row2 = plugin->input->get_h();
329                 }
330         }
332 LoadClient* HueEngine::new_client()
334         return new HueUnit(plugin, this);
336 LoadPackage* HueEngine::new_package()
338         return new HuePackage;
348 HuePackage::HuePackage()
349  : LoadPackage()
353 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
354  : LoadClient(server)
356         this->plugin = plugin;
365 #define HUESATURATION(type, max, components, use_yuv) \
366 { \
367         float h_offset = plugin->config.hue; \
368         float s_offset = ((float)plugin->config.saturation - MINSATURATION) / MAXSATURATION; \
369         float v_offset = ((float)plugin->config.value - MINVALUE) / MAXVALUE; \
370         for(int i = pkg->row1; i < pkg->row2; i++) \
371         { \
372                 type* in_row = (type*)plugin->input->get_rows()[i]; \
373                 type* out_row = (type*)plugin->output->get_rows()[i]; \
375                 for(int j = 0; j < w; j++) \
376                 { \
377                         float h, s, va; \
378                         int y, u, v; \
379                         float r, g, b; \
380                         int r_i, g_i, b_i; \
382                         if(use_yuv) \
383                         { \
384                                 y = (int)in_row[0]; \
385                                 u = (int)in_row[1]; \
386                                 v = (int)in_row[2]; \
387                                 if(max == 0xffff) \
388                                         yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
389                                 else \
390                                         yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
391                                 HSV::rgb_to_hsv((float)r_i / max, \
392                                         (float)g_i / max, \
393                                         (float)b_i / max, \
394                                         h, \
395                                         s, \
396                                         va); \
397                         } \
398                         else \
399                         { \
400                                 r = (float)in_row[0] / max; \
401                                 g = (float)in_row[1] / max; \
402                                 b = (float)in_row[2] / max; \
403                                 HSV::rgb_to_hsv(r, g, b, h, s, va); \
404                         } \
407                         h += h_offset; \
408                         s *= s_offset; \
409                         va *= v_offset; \
411                         if(h >= 360) h -= 360; \
412                         if(h < 0) h += 360; \
413                         if(sizeof(type) < 4) \
414                         { \
415                                 if(s > 1) s = 1; \
416                                 if(va > 1) va = 1; \
417                                 if(s < 0) s = 0; \
418                                 if(va < 0) va = 0; \
419                         } \
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                                 if(sizeof(type) < 4) \
432                                 { \
433                                         r *= max; \
434                                         g *= max; \
435                                         b *= max; \
436                                         out_row[0] = (type)CLIP(r, 0, max); \
437                                         out_row[1] = (type)CLIP(g, 0, max); \
438                                         out_row[2] = (type)CLIP(b, 0, max); \
439                                 } \
440                                 else \
441                                 { \
442                                         out_row[0] = (type)r; \
443                                         out_row[1] = (type)g; \
444                                         out_row[2] = (type)b; \
445                                 } \
446                         } \
448                         in_row += components; \
449                         out_row += components; \
450                 } \
451         } \
455 void HueUnit::process_package(LoadPackage *package)
457         HuePackage *pkg = (HuePackage*)package;
458         int w = plugin->input->get_w();
460         switch(plugin->input->get_color_model())
461         {
462                 case BC_RGB888:
463                         HUESATURATION(unsigned char, 0xff, 3, 0)
464                         break;
466                 case BC_RGB_FLOAT:
467                         HUESATURATION(float, 1, 3, 0)
468                         break;
470                 case BC_YUV888:
471                         HUESATURATION(unsigned char, 0xff, 3, 1)
472                         break;
474                 case BC_RGB161616:
475                         HUESATURATION(uint16_t, 0xffff, 3, 0)
476                         break;
478                 case BC_YUV161616:
479                         HUESATURATION(uint16_t, 0xffff, 3, 1)
480                         break;
482                 case BC_RGBA_FLOAT:
483                         HUESATURATION(float, 1, 4, 0)
484                         break;
486                 case BC_RGBA8888:
487                         HUESATURATION(unsigned char, 0xff, 4, 0)
488                         break;
490                 case BC_YUVA8888:
491                         HUESATURATION(unsigned char, 0xff, 4, 1)
492                         break;
494                 case BC_RGBA16161616:
495                         HUESATURATION(uint16_t, 0xffff, 4, 0)
496                         break;
498                 case BC_YUVA16161616:
499                         HUESATURATION(uint16_t, 0xffff, 4, 1)
500                         break;
502         }
508 REGISTER_PLUGIN(HueEffect)
511 HueEffect::HueEffect(PluginServer *server)
512  : PluginVClient(server)
514         engine = 0;
515         PLUGIN_CONSTRUCTOR_MACRO
517 HueEffect::~HueEffect()
519         PLUGIN_DESTRUCTOR_MACRO
520         if(engine) delete engine;
523 int HueEffect::process_realtime(VFrame *input, VFrame *output)
525         load_configuration();
526         this->input = input;
527         this->output = output;
528         if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
529         {
530                 if(input->get_rows()[0] != output->get_rows()[0])
531                         output->copy_from(input);
532         }
533         else
534         {
535                 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
536                 
537                 engine->process_packages();
538         }
539         return 0;
542 char* HueEffect::plugin_title() { return N_("Hue saturation"); }
543 int HueEffect::is_realtime() { return 1; }
545 NEW_PICON_MACRO(HueEffect)
546 SHOW_GUI_MACRO(HueEffect, HueThread)
547 SET_STRING_MACRO(HueEffect)
548 RAISE_WINDOW_MACRO(HueEffect)
549 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
551 int HueEffect::load_defaults()
553         char directory[BCTEXTLEN];
554         sprintf(directory, "%shuesaturation.rc", BCASTDIR);
555         defaults = new Defaults(directory);
556         defaults->load();
557         config.hue = defaults->get("HUE", config.hue);
558         config.saturation = defaults->get("SATURATION", config.saturation);
559         config.value = defaults->get("VALUE", config.value);
560         return 0;
562 int HueEffect::save_defaults()
564         defaults->update("HUE", config.hue);
565         defaults->update("SATURATION", config.saturation);
566         defaults->update("VALUE", config.value);
567         defaults->save();
568         return 0;
570 void HueEffect::save_data(KeyFrame *keyframe)
572         FileXML output;
573         output.set_shared_string(keyframe->data, MESSAGESIZE);
574         output.tag.set_title("HUESATURATION");
575         output.tag.set_property("HUE", config.hue);
576         output.tag.set_property("SATURATION", config.saturation);
577         output.tag.set_property("VALUE", config.value);
578         output.append_tag();
579         output.terminate_string();
581 void HueEffect::read_data(KeyFrame *keyframe)
583         FileXML input;
584         input.set_shared_string(keyframe->data, strlen(keyframe->data));
585         while(!input.read_tag())
586         {
587                 if(input.tag.title_is("HUESATURATION"))
588                 {
589                         config.hue = input.tag.get_property("HUE", config.hue);
590                         config.saturation = input.tag.get_property("SATURATION", config.saturation);
591                         config.value = input.tag.get_property("VALUE", config.value);
592                 }
593         }
595 void HueEffect::update_gui()
597         if(thread)
598         {
599                 thread->window->lock_window();
600                 load_configuration();
601                 thread->window->hue->update(config.hue);
602                 thread->window->saturation->update(config.saturation);
603                 thread->window->value->update(config.value);
604                 thread->window->unlock_window();
605         }