r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / oilpainting / oil.C
bloba4aca248e0cd040d2a48d0eda4d894298ecaa04a
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 "language.h"
8 #include "loadbalance.h"
9 #include "picon_png.h"
10 #include "pluginvclient.h"
11 #include "vframe.h"
13 #include <math.h>
14 #include <stdint.h>
15 #include <string.h>
20 // Algorithm by Torsten Martinsen
21 // Ported to Cinelerra by Heroine Virtual Ltd.
26 class OilEffect;
30 class OilConfig
32 public:
33         OilConfig();
34         void copy_from(OilConfig &src);
35         int equivalent(OilConfig &src);
36         void interpolate(OilConfig &prev, 
37                 OilConfig &next, 
38                 long prev_frame, 
39                 long next_frame, 
40                 long current_frame);
41         float radius;
42         int use_intensity;
45 class OilRadius : public BC_FSlider
47 public:
48         OilRadius(OilEffect *plugin, int x, int y);
49         int handle_event();
50         OilEffect *plugin;
54 class OilIntensity : public BC_CheckBox
56 public:
57         OilIntensity(OilEffect *plugin, int x, int y);
58         int handle_event();
59         OilEffect *plugin;
62 class OilWindow : public BC_Window
64 public:
65         OilWindow(OilEffect *plugin, int x, int y);
66         ~OilWindow();
67         void create_objects();
68         int close_event();
69         OilEffect *plugin;
70         OilRadius *radius;
71         OilIntensity *intensity;
74 PLUGIN_THREAD_HEADER(OilEffect, OilThread, OilWindow)
80 class OilServer : public LoadServer
82 public:
83         OilServer(OilEffect *plugin, int cpus);
84         void init_packages();
85         LoadClient* new_client();
86         LoadPackage* new_package();
87         OilEffect *plugin;
90 class OilPackage : public LoadPackage
92 public:
93         OilPackage();
94         int row1, row2;
97 class OilUnit : public LoadClient
99 public:
100         OilUnit(OilEffect *plugin, OilServer *server);
101         void process_package(LoadPackage *package);
102         OilEffect *plugin;
113 class OilEffect : public PluginVClient
115 public:
116         OilEffect(PluginServer *server);
117         ~OilEffect();
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();
133         OilConfig config;
134         VFrame *temp_frame;
135         VFrame *input, *output;
136         Defaults *defaults;
137         OilThread *thread;
138         OilServer *engine;
139         int need_reconfigure;
154 OilConfig::OilConfig()
156         radius = 5;
157         use_intensity = 0;
160 void OilConfig::copy_from(OilConfig &src)
162         this->radius = src.radius;
163         this->use_intensity = src.use_intensity;
166 int OilConfig::equivalent(OilConfig &src)
168         return (EQUIV(this->radius, src.radius) &&
169                 this->use_intensity == src.use_intensity);
172 void OilConfig::interpolate(OilConfig &prev, 
173                 OilConfig &next, 
174                 long prev_frame, 
175                 long next_frame, 
176                 long current_frame)
178         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
179         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
180         this->radius = prev.radius * prev_scale + next.radius * next_scale;
181         this->use_intensity = prev.use_intensity;
182 // printf("OilConfig::interpolate prev_frame=%ld current_frame=%ld next_frame=%ld prev.radius=%f this->radius=%f next.radius=%f\n", 
183 //      prev_frame, current_frame, next_frame, prev.radius, this->radius, next.radius);
197 OilRadius::OilRadius(OilEffect *plugin, int x, int y)
198  : BC_FSlider(x, 
199                 y, 
200                 0,
201                 200,
202                 200, 
203                 (float)0, 
204                 (float)30,
205                 plugin->config.radius)
207         this->plugin = plugin;
209 int OilRadius::handle_event()
211         plugin->config.radius = get_value();
212         plugin->send_configure_change();
213         return 1;
222 OilIntensity::OilIntensity(OilEffect *plugin, int x, int y)
223  : BC_CheckBox(x, y, plugin->config.use_intensity, _("Use intensity"))
225         this->plugin = plugin;
227 int OilIntensity::handle_event()
229         plugin->config.use_intensity = get_value();
230         plugin->send_configure_change();
231         return 1;
240 OilWindow::OilWindow(OilEffect *plugin, int x, int y)
241  : BC_Window(plugin->gui_string, 
242         x, 
243         y, 
244         300, 
245         160, 
246         300, 
247         160, 
248         0, 
249         0,
250         1)
252         this->plugin = plugin;
255 OilWindow::~OilWindow()
259 void OilWindow::create_objects()
261         int x = 10, y = 10;
262         add_subwindow(new BC_Title(x, y, _("Radius:")));
263         add_subwindow(radius = new OilRadius(plugin, x + 70, y));
264         y += 40;
265         add_subwindow(intensity = new OilIntensity(plugin, x, y));
266         
267         show_window();
268         flush();
271 WINDOW_CLOSE_EVENT(OilWindow)
275 PLUGIN_THREAD_OBJECT(OilEffect, OilThread, OilWindow)
280 REGISTER_PLUGIN(OilEffect)
285 OilEffect::OilEffect(PluginServer *server)
286  : PluginVClient(server)
288         temp_frame = 0;
289         need_reconfigure = 1;
290         engine = 0;
291         PLUGIN_CONSTRUCTOR_MACRO
294 OilEffect::~OilEffect()
296         PLUGIN_DESTRUCTOR_MACRO
298         if(temp_frame) delete temp_frame;
299         if(engine) delete engine;
303 char* OilEffect::plugin_title() { return N_("Oil painting"); }
304 int OilEffect::is_realtime() { return 1; }
307 NEW_PICON_MACRO(OilEffect)
309 SHOW_GUI_MACRO(OilEffect, OilThread)
311 RAISE_WINDOW_MACRO(OilEffect)
313 SET_STRING_MACRO(OilEffect)
315 void OilEffect::update_gui()
317         if(thread)
318         {
319                 thread->window->lock_window();
320                 load_configuration();
321 //printf("OilEffect::update_gui 1 %ld %f\n", get_source_position(), config.radius);
323                 thread->window->radius->update(config.radius);
324                 thread->window->intensity->update(config.use_intensity);
325                 thread->window->unlock_window();
326         }
330 LOAD_CONFIGURATION_MACRO(OilEffect, OilConfig)
332 int OilEffect::load_defaults()
334         char directory[BCTEXTLEN];
335 // set the default directory
336         sprintf(directory, "%soilpainting.rc", BCASTDIR);
338 // load the defaults
339         defaults = new Defaults(directory);
340         defaults->load();
342         config.radius = defaults->get("RADIUS", config.radius);
343         config.use_intensity = defaults->get("USE_INTENSITY", config.use_intensity);
344         return 0;
347 int OilEffect::save_defaults()
349         defaults->update("RADIUS", config.radius);
350         defaults->update("USE_INTENSITY", config.use_intensity);
351         defaults->save();
352         return 0;
355 void OilEffect::save_data(KeyFrame *keyframe)
357         FileXML output;
359 // cause data to be stored directly in text
360         output.set_shared_string(keyframe->data, MESSAGESIZE);
361         output.tag.set_title("OIL_PAINTING");
362         output.tag.set_property("RADIUS", config.radius);
363         output.tag.set_property("USE_INTENSITY", config.use_intensity);
364         output.append_tag();
365         output.terminate_string();
368 void OilEffect::read_data(KeyFrame *keyframe)
370         FileXML input;
372         input.set_shared_string(keyframe->data, strlen(keyframe->data));
374         int result = 0;
376         while(!input.read_tag())
377         {
378                 if(input.tag.title_is("OIL_PAINTING"))
379                 {
380                         config.radius = input.tag.get_property("RADIUS", config.radius);
381                         config.use_intensity = input.tag.get_property("USE_INTENSITY", config.use_intensity);
382                 }
383         }
387 int OilEffect::process_realtime(VFrame *input, VFrame *output)
389         need_reconfigure |= load_configuration();
393 //printf("OilEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
394         this->input = input;
395         this->output = output;
397         if(EQUIV(config.radius, 0))
398         {
399                 if(input->get_rows()[0] != output->get_rows()[0])
400                         output->copy_from(input);
401         }
402         else
403         {
404                 if(input->get_rows()[0] == output->get_rows()[0])
405                 {
406                         if(!temp_frame) temp_frame = new VFrame(0,
407                                 input->get_w(),
408                                 input->get_h(),
409                                 input->get_color_model());
410                         temp_frame->copy_from(input);
411                         this->input = temp_frame;
412                 }
413                 
414                 
415                 if(!engine)
416                 {
417                         engine = new OilServer(this, (PluginClient::smp + 1));
418                 }
419                 
420                 engine->process_packages();
421         }
422         
423         
424         
425         return 0;
433 OilPackage::OilPackage()
434  : LoadPackage()
443 OilUnit::OilUnit(OilEffect *plugin, OilServer *server)
444  : LoadClient(server)
446         this->plugin = plugin;
450 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
451                                                                         ((p)[1] * 150) + \
452                                                                         ((p)[2] * 29)) >> 8)
455 #define OIL_MACRO(type, hist_size, components) \
456 { \
457         type *src, *dest; \
458         type val[components]; \
459         int count[components], count2; \
460         int *hist[components]; \
461         int *hist2; \
462         type **src_rows = (type**)plugin->input->get_rows(); \
464         for(int i = 0; i < components; i++) \
465                 hist[i] = new int[hist_size + 1]; \
466         hist2 = new int[hist_size + 1]; \
468 printf("1\n"); \
469         for(int y1 = pkg->row1; y1 < pkg->row2; y1++) \
470         { \
471                 dest = (type*)plugin->output->get_rows()[y1]; \
473 printf("2 %d\n", y1); \
474                 if(!plugin->config.use_intensity) \
475                 { \
476                         for(int x1 = 0; x1 < w; x1++) \
477                         { \
478                                 bzero(count, sizeof(count)); \
479                                 bzero(val, sizeof(val)); \
480                                 bzero(hist[0], sizeof(int) * (hist_size + 1)); \
481                                 bzero(hist[1], sizeof(int) * (hist_size + 1)); \
482                                 bzero(hist[2], sizeof(int) * (hist_size + 1)); \
484                                 int x3 = CLIP((x1 - n), 0, w - 1); \
485                                 int y3 = CLIP((y1 - n), 0, h - 1); \
486                                 int x4 = CLIP((x1 + n + 1), 0, w - 1); \
487                                 int y4 = CLIP((y1 + n + 1), 0, h - 1); \
489                                 for(int y2 = y3; y2 < y4; y2++) \
490                                 { \
491                                         src = src_rows[y2]; \
492                                         for(int x2 = x3; x2 < x4; x2++) \
493                                         { \
494                                                 int c; \
495                                                 int subscript; \
496                                                 type value; \
498                         value = src[x2 * components + 0]; \
499                                                 if(sizeof(type) == 4) \
500                                                 { \
501                                                         subscript = (int)(value * hist_size); \
502                                                         CLAMP(subscript, 0, hist_size); \
503                                                 } \
504                                                 else \
505                                                         subscript = (int)value; \
507                                                 if((c = ++hist[0][subscript]) > count[0]) \
508                                                 { \
509                                                         val[0] = value; \
510                                                         count[0] = c; \
511                                                 } \
513                         value = src[x2 * components + 1]; \
514                                                 if(sizeof(type) == 4) \
515                                                 { \
516                                                         subscript = (int)(value * hist_size); \
517                                                         CLAMP(subscript, 0, hist_size); \
518                                                 } \
519                                                 else \
520                                                         subscript = (int)value; \
522                                                 if((c = ++hist[1][subscript]) > count[1]) \
523                                                 { \
524                                                         val[1] = value; \
525                                                         count[1] = c; \
526                                                 } \
528                         value = src[x2 * components + 2]; \
529                                                 if(sizeof(type) == 4) \
530                                                 { \
531                                                         subscript = (int)(value * hist_size); \
532                                                         CLAMP(subscript, 0, hist_size); \
533                                                 } \
534                                                 else \
535                                                         subscript = (int)value; \
537                                                 if((c = ++hist[2][subscript]) > count[2]) \
538                                                 { \
539                                                         val[2] = value; \
540                                                         count[2] = c; \
541                                                 } \
543                                                 if(components == 4) \
544                                                 { \
545                                 value = src[x2 * components + 3]; \
546                                                         if(sizeof(type) == 4) \
547                                                         { \
548                                                                 subscript = (int)(value * hist_size); \
549                                                                 CLAMP(subscript, 0, hist_size); \
550                                                         } \
551                                                         else \
552                                                                 subscript = (int)value; \
554                                                         if((c = ++hist[3][subscript]) > count[3]) \
555                                                         { \
556                                                                 val[3] = value; \
557                                                                 count[3] = c; \
558                                                         } \
559                                                 } \
560                                         } \
561                                 } \
563                                 dest[x1 * components + 0] = val[0]; \
564                                 dest[x1 * components + 1] = val[1]; \
565                                 dest[x1 * components + 2] = val[2]; \
566                                 if(components == 4) dest[x1 * components + 3] = val[3]; \
567                         } \
568                 } \
569                 else \
570                 { \
571                         for(int x1 = 0; x1 < w; x1++) \
572                         { \
573                                 count2 = 0; \
574                                 bzero(val, sizeof(val)); \
575                                 bzero(hist2, sizeof(int) * (hist_size + 1)); \
577                                 int x3 = CLIP((x1 - n), 0, w - 1); \
578                         int y3 = CLIP((y1 - n), 0, h - 1); \
579                         int x4 = CLIP((x1 + n + 1), 0, w - 1); \
580                         int y4 = CLIP((y1 + n + 1), 0, h - 1); \
582                                 for(int y2 = y3; y2 < y4; y2++) \
583                                 { \
584                                         src = src_rows[y2]; \
585                                         for(int x2 = x3; x2 < x4; x2++) \
586                                         { \
587                                                 int c; \
588                                                 if((c = ++hist2[INTENSITY(src + x2 * components)]) > count2) \
589                                                 { \
590                                                         val[0] = src[x2 * components + 0]; \
591                                                         val[1] = src[x2 * components + 1]; \
592                                                         val[2] = src[x2 * components + 2]; \
593                                                         if(components == 3) val[3] = src[x2 * components + 3]; \
594                                                         count2 = c; \
595                                                 } \
596                                         } \
597                                 } \
599                                 dest[x1 * components + 0] = val[0]; \
600                                 dest[x1 * components + 1] = val[1]; \
601                                 dest[x1 * components + 2] = val[2]; \
602                                 if(components == 3) dest[x1 * components + 3] = val[3]; \
603                         } \
604                 } \
605         } \
607         for(int i = 0; i < components; i++) \
608                 delete [] hist[i]; \
609         delete [] hist2; \
610 printf("10\n"); \
616 void OilUnit::process_package(LoadPackage *package)
618         OilPackage *pkg = (OilPackage*)package;
619         int w = plugin->input->get_w();
620         int h = plugin->input->get_h();
621         int n = (int)(plugin->config.radius / 2);
623         switch(plugin->input->get_color_model())
624         {
625                 case BC_RGB_FLOAT:
626                         OIL_MACRO(float, 0xffff, 3)
627                         break;
628                 case BC_RGB888:
629                 case BC_YUV888:
630                         OIL_MACRO(unsigned char, 0xff, 3)
631                         break;
632                 case BC_RGB161616:
633                 case BC_YUV161616:
634                         OIL_MACRO(uint16_t, 0xffff, 3)
635                         break;
636                 case BC_RGBA_FLOAT:
637                         OIL_MACRO(float, 0xffff, 4)
638                         break;
639                 case BC_RGBA8888:
640                 case BC_YUVA8888:
641                         OIL_MACRO(unsigned char, 0xff, 4)
642                         break;
643                 case BC_RGBA16161616:
644                 case BC_YUVA16161616:
645                         OIL_MACRO(uint16_t, 0xffff, 4)
646                         break;
647         }
659 OilServer::OilServer(OilEffect *plugin, int cpus)
660  : LoadServer(cpus, cpus)
662         this->plugin = plugin;
665 void OilServer::init_packages()
667         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
668         int y = 0;
669         for(int i = 0; i < LoadServer::total_packages; i++)
670         {
671                 OilPackage *pkg = (OilPackage*)packages[i];
672                 pkg->row1 = y;
673                 pkg->row2 = y + increment;
674                 y += increment;
675                 if(pkg->row2 > plugin->input->get_h())
676                 {
677                         y = pkg->row2 = plugin->input->get_h();
678                 }
679         }
683 LoadClient* OilServer::new_client()
685         return new OilUnit(plugin, this);
688 LoadPackage* OilServer::new_package()
690         return new OilPackage;