r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / oilpainting / oil.C
blob48cad94f67757633bea8bc2696cbcb335598f61e
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "keyframe.h"
7 #include "loadbalance.h"
8 #include "picon_png.h"
9 #include "pluginvclient.h"
10 #include "vframe.h"
12 #include <math.h>
13 #include <stdint.h>
14 #include <string.h>
16 #include <libintl.h>
17 #define _(String) gettext(String)
18 #define gettext_noop(String) String
19 #define N_(String) gettext_noop (String)
23 // Algorithm by Torsten Martinsen
24 // Ported to Cinelerra by Heroine Virtual Ltd.
29 class OilEffect;
33 class OilConfig
35 public:
36         OilConfig();
37         void copy_from(OilConfig &src);
38         int equivalent(OilConfig &src);
39         void interpolate(OilConfig &prev, 
40                 OilConfig &next, 
41                 long prev_frame, 
42                 long next_frame, 
43                 long current_frame);
44         float radius;
45         int use_intensity;
48 class OilRadius : public BC_FSlider
50 public:
51         OilRadius(OilEffect *plugin, int x, int y);
52         int handle_event();
53         OilEffect *plugin;
57 class OilIntensity : public BC_CheckBox
59 public:
60         OilIntensity(OilEffect *plugin, int x, int y);
61         int handle_event();
62         OilEffect *plugin;
65 class OilWindow : public BC_Window
67 public:
68         OilWindow(OilEffect *plugin, int x, int y);
69         ~OilWindow();
70         void create_objects();
71         int close_event();
72         OilEffect *plugin;
73         OilRadius *radius;
74         OilIntensity *intensity;
77 PLUGIN_THREAD_HEADER(OilEffect, OilThread, OilWindow)
83 class OilServer : public LoadServer
85 public:
86         OilServer(OilEffect *plugin, int cpus);
87         void init_packages();
88         LoadClient* new_client();
89         LoadPackage* new_package();
90         OilEffect *plugin;
93 class OilPackage : public LoadPackage
95 public:
96         OilPackage();
97         int row1, row2;
100 class OilUnit : public LoadClient
102 public:
103         OilUnit(OilEffect *plugin, OilServer *server);
104         void process_package(LoadPackage *package);
105         OilEffect *plugin;
116 class OilEffect : public PluginVClient
118 public:
119         OilEffect(PluginServer *server);
120         ~OilEffect();
122         int process_realtime(VFrame *input, VFrame *output);
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();
136         OilConfig config;
137         VFrame *temp_frame;
138         VFrame *input, *output;
139         Defaults *defaults;
140         OilThread *thread;
141         OilServer *engine;
142         int need_reconfigure;
157 OilConfig::OilConfig()
159         radius = 5;
160         use_intensity = 0;
163 void OilConfig::copy_from(OilConfig &src)
165         this->radius = src.radius;
166         this->use_intensity = src.use_intensity;
169 int OilConfig::equivalent(OilConfig &src)
171         return (EQUIV(this->radius, src.radius) &&
172                 this->use_intensity == src.use_intensity);
175 void OilConfig::interpolate(OilConfig &prev, 
176                 OilConfig &next, 
177                 long prev_frame, 
178                 long next_frame, 
179                 long current_frame)
181         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
182         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
183         this->radius = prev.radius * prev_scale + next.radius * next_scale;
184         this->use_intensity = prev.use_intensity;
185 // printf("OilConfig::interpolate prev_frame=%ld current_frame=%ld next_frame=%ld prev.radius=%f this->radius=%f next.radius=%f\n", 
186 //      prev_frame, current_frame, next_frame, prev.radius, this->radius, next.radius);
200 OilRadius::OilRadius(OilEffect *plugin, int x, int y)
201  : BC_FSlider(x, 
202                 y, 
203                 0,
204                 200,
205                 200, 
206                 (float)0, 
207                 (float)30,
208                 plugin->config.radius)
210         this->plugin = plugin;
212 int OilRadius::handle_event()
214         plugin->config.radius = get_value();
215         plugin->send_configure_change();
216         return 1;
225 OilIntensity::OilIntensity(OilEffect *plugin, int x, int y)
226  : BC_CheckBox(x, y, plugin->config.use_intensity, _("Use intensity"))
228         this->plugin = plugin;
230 int OilIntensity::handle_event()
232         plugin->config.use_intensity = get_value();
233         plugin->send_configure_change();
234         return 1;
243 OilWindow::OilWindow(OilEffect *plugin, int x, int y)
244  : BC_Window(plugin->gui_string, 
245         x, 
246         y, 
247         300, 
248         160, 
249         300, 
250         160, 
251         0, 
252         0,
253         1)
255         this->plugin = plugin;
258 OilWindow::~OilWindow()
262 void OilWindow::create_objects()
264         int x = 10, y = 10;
265         add_subwindow(new BC_Title(x, y, _("Radius:")));
266         add_subwindow(radius = new OilRadius(plugin, x + 70, y));
267         y += 40;
268         add_subwindow(intensity = new OilIntensity(plugin, x, y));
269         
270         show_window();
271         flush();
274 int OilWindow::close_event()
276         set_done(1);
277         return 1;
282 PLUGIN_THREAD_OBJECT(OilEffect, OilThread, OilWindow)
287 REGISTER_PLUGIN(OilEffect)
292 OilEffect::OilEffect(PluginServer *server)
293  : PluginVClient(server)
295         temp_frame = 0;
296         need_reconfigure = 1;
297         engine = 0;
298         PLUGIN_CONSTRUCTOR_MACRO
301 OilEffect::~OilEffect()
303         PLUGIN_DESTRUCTOR_MACRO
305         if(temp_frame) delete temp_frame;
306         if(engine) delete engine;
310 int OilEffect::is_realtime()
312         return 1;
315 char* OilEffect::plugin_title()
317         return _("Oil painting");
320 NEW_PICON_MACRO(OilEffect)
322 SHOW_GUI_MACRO(OilEffect, OilThread)
324 RAISE_WINDOW_MACRO(OilEffect)
326 SET_STRING_MACRO(OilEffect)
328 void OilEffect::update_gui()
330         if(thread)
331         {
332                 thread->window->lock_window();
333                 load_configuration();
334 //printf("OilEffect::update_gui 1 %ld %f\n", get_source_position(), config.radius);
336                 thread->window->radius->update(config.radius);
337                 thread->window->intensity->update(config.use_intensity);
338                 thread->window->unlock_window();
339         }
343 LOAD_CONFIGURATION_MACRO(OilEffect, OilConfig)
345 int OilEffect::load_defaults()
347         char directory[BCTEXTLEN];
348 // set the default directory
349         sprintf(directory, "%soilpainting.rc", BCASTDIR);
351 // load the defaults
352         defaults = new Defaults(directory);
353         defaults->load();
355         config.radius = defaults->get("RADIUS", config.radius);
356         config.use_intensity = defaults->get("USE_INTENSITY", config.use_intensity);
357         return 0;
360 int OilEffect::save_defaults()
362         defaults->update("RADIUS", config.radius);
363         defaults->update("USE_INTENSITY", config.use_intensity);
364         defaults->save();
365         return 0;
368 void OilEffect::save_data(KeyFrame *keyframe)
370         FileXML output;
372 // cause data to be stored directly in text
373         output.set_shared_string(keyframe->data, MESSAGESIZE);
374         output.tag.set_title("OIL_PAINTING");
375         output.tag.set_property("RADIUS", config.radius);
376         output.tag.set_property("USE_INTENSITY", config.use_intensity);
377         output.append_tag();
378         output.terminate_string();
381 void OilEffect::read_data(KeyFrame *keyframe)
383         FileXML input;
385         input.set_shared_string(keyframe->data, strlen(keyframe->data));
387         int result = 0;
389         while(!input.read_tag())
390         {
391                 if(input.tag.title_is("OIL_PAINTING"))
392                 {
393                         config.radius = input.tag.get_property("RADIUS", config.radius);
394                         config.use_intensity = input.tag.get_property("USE_INTENSITY", config.use_intensity);
395                 }
396         }
400 int OilEffect::process_realtime(VFrame *input, VFrame *output)
402         need_reconfigure |= load_configuration();
406 //printf("OilEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
407         this->input = input;
408         this->output = output;
410         if(EQUIV(config.radius, 0))
411         {
412                 if(input->get_rows()[0] != output->get_rows()[0])
413                         output->copy_from(input);
414         }
415         else
416         {
417                 if(input->get_rows()[0] == output->get_rows()[0])
418                 {
419                         if(!temp_frame) temp_frame = new VFrame(0,
420                                 input->get_w(),
421                                 input->get_h(),
422                                 input->get_color_model());
423                         temp_frame->copy_from(input);
424                         this->input = temp_frame;
425                 }
426                 
427                 
428                 if(!engine)
429                 {
430                         engine = new OilServer(this, (PluginClient::smp + 1));
431                 }
432                 
433                 engine->process_packages();
434         }
435         
436         
437         
438         return 0;
446 OilPackage::OilPackage()
447  : LoadPackage()
456 OilUnit::OilUnit(OilEffect *plugin, OilServer *server)
457  : LoadClient(server)
459         this->plugin = plugin;
463 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
464                                                                         ((p)[1] * 150) + \
465                                                                         ((p)[2] * 29)) >> 8)
468 #define OIL_MACRO(type, max, components) \
469 { \
470         type *src, *dest; \
471         type Val[components]; \
472         type Cnt[components], Cnt2; \
473         type Hist[components][max + 1], Hist2[max + 1]; \
474         type **src_rows = (type**)plugin->input->get_rows(); \
476         for(int y1 = pkg->row1; y1 < pkg->row2; y1++) \
477         { \
478                 dest = (type*)plugin->output->get_rows()[y1]; \
480                 if(!plugin->config.use_intensity) \
481                 { \
482                         for(int x1 = 0; x1 < w; x1++) \
483                         { \
484                                 bzero(Cnt, sizeof(Cnt)); \
485                                 bzero(Val, sizeof(Val)); \
486                                 bzero(Hist, sizeof(Hist)); \
488                                 int x3 = CLIP((x1 - n), 0, w - 1); \
489                                 int y3 = CLIP((y1 - n), 0, h - 1); \
490                                 int x4 = CLIP((x1 + n + 1), 0, w - 1); \
491                                 int y4 = CLIP((y1 + n + 1), 0, h - 1); \
493                                 for(int y2 = y3; y2 < y4; y2++) \
494                                 { \
495                                         src = src_rows[y2]; \
496                                         for(int x2 = x3; x2 < x4; x2++) \
497                                         { \
498                                                 int c; \
499                                                 if((c = ++Hist[0][src[x2 * components + 0]]) > Cnt[0]) \
500                                                 { \
501                                                         Val[0] = src[x2 * components + 0]; \
502                                                         Cnt[0] = c; \
503                                                 } \
505                                                 if((c = ++Hist[1][src[x2 * components + 1]]) > Cnt[1]) \
506                                                 { \
507                                                         Val[1] = src[x2 * components + 1]; \
508                                                         Cnt[1] = c; \
509                                                 } \
511                                                 if((c = ++Hist[2][src[x2 * components + 2]]) > Cnt[2]) \
512                                                 { \
513                                                         Val[2] = src[x2 * components + 2]; \
514                                                         Cnt[2] = c; \
515                                                 } \
517                                                 if(components == 4) \
518                                                 { \
519                                                         if((c = ++Hist[3][src[x2 * components + 3]]) > Cnt[3]) \
520                                                         { \
521                                                                 Val[3] = src[x2 * components + 3]; \
522                                                                 Cnt[3] = c; \
523                                                         } \
524                                                 } \
525                                         } \
526                                 } \
528                                 dest[x1 * components + 0] = Val[0]; \
529                                 dest[x1 * components + 1] = Val[1]; \
530                                 dest[x1 * components + 2] = Val[2]; \
531                                 if(components == 4) dest[x1 * components + 3] = Val[3]; \
532                         } \
533                 } \
534                 else \
535                 { \
536                         for(int x1 = 0; x1 < w; x1++) \
537                         { \
538                                 Cnt2 = 0; \
539                                 bzero(Val, sizeof(Val)); \
540                                 bzero(Hist2, sizeof(Hist2)); \
542                                 int x3 = CLIP((x1 - n), 0, w - 1); \
543                         int y3 = CLIP((y1 - n), 0, h - 1); \
544                         int x4 = CLIP((x1 + n + 1), 0, w - 1); \
545                         int y4 = CLIP((y1 + n + 1), 0, h - 1); \
547                                 for(int y2 = y3; y2 < y4; y2++) \
548                                 { \
549                                         src = src_rows[y2]; \
550                                         for(int x2 = x3; x2 < x4; x2++) \
551                                         { \
552                                                 int c; \
553                                                 if((c = ++Hist2[INTENSITY(src + x2 * components)]) > Cnt2) \
554                                                 { \
555                                                         Val[0] = src[x2 * components + 0]; \
556                                                         Val[1] = src[x2 * components + 1]; \
557                                                         Val[2] = src[x2 * components + 2]; \
558                                                         if(components == 3) Val[3] = src[x2 * components + 3]; \
559                                                         Cnt2 = c; \
560                                                 } \
561                                         } \
562                                 } \
564                                 dest[x1 * components + 0] = Val[0]; \
565                                 dest[x1 * components + 1] = Val[1]; \
566                                 dest[x1 * components + 2] = Val[2]; \
567                                 if(components == 3) dest[x1 * components + 3] = Val[3]; \
568                         } \
569                 } \
570         } \
576 void OilUnit::process_package(LoadPackage *package)
578         OilPackage *pkg = (OilPackage*)package;
579         int w = plugin->input->get_w();
580         int h = plugin->input->get_h();
581         int n = (int)(plugin->config.radius / 2);
583         switch(plugin->input->get_color_model())
584         {
585                 case BC_RGB888:
586                 case BC_YUV888:
587                         OIL_MACRO(unsigned char, 0xff, 3)
588                         break;
589                 case BC_RGB161616:
590                 case BC_YUV161616:
591                         OIL_MACRO(uint16_t, 0xffff, 3)
592                         break;
593                 case BC_RGBA8888:
594                 case BC_YUVA8888:
595                         OIL_MACRO(unsigned char, 0xff, 4)
596                         break;
597                 case BC_RGBA16161616:
598                 case BC_YUVA16161616:
599                         OIL_MACRO(uint16_t, 0xffff, 4)
600                         break;
601         }
613 OilServer::OilServer(OilEffect *plugin, int cpus)
614  : LoadServer(cpus, cpus)
616         this->plugin = plugin;
619 void OilServer::init_packages()
621         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
622         int y = 0;
623         for(int i = 0; i < LoadServer::total_packages; i++)
624         {
625                 OilPackage *pkg = (OilPackage*)packages[i];
626                 pkg->row1 = y;
627                 pkg->row2 = y + increment;
628                 y += increment;
629                 if(pkg->row2 > plugin->input->get_h())
630                 {
631                         y = pkg->row2 = plugin->input->get_h();
632                 }
633         }
637 LoadClient* OilServer::new_client()
639         return new OilUnit(plugin, this);
642 LoadPackage* OilServer::new_package()
644         return new OilPackage;