add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / oilpainting / oil.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "loadbalance.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33 #include <math.h>
34 #include <stdint.h>
35 #include <string.h>
36
37
38
39
40 // Algorithm by Torsten Martinsen
41 // Ported to Cinelerra by Heroine Virtual Ltd.
42
43
44
45
46 class OilEffect;
47 class OilWindow;
48 class OilReset;
49
50
51 class OilConfig
52 {
53 public:
54         OilConfig();
55         void reset();
56
57         void copy_from(OilConfig &src);
58         int equivalent(OilConfig &src);
59         void interpolate(OilConfig &prev,
60                 OilConfig &next,
61                 long prev_frame,
62                 long next_frame,
63                 long current_frame);
64         float radius;
65         int use_intensity;
66 };
67
68 class OilRadius : public BC_FSlider
69 {
70 public:
71         OilRadius(OilEffect *plugin, int x, int y);
72         int handle_event();
73         OilEffect *plugin;
74 };
75
76
77 class OilIntensity : public BC_CheckBox
78 {
79 public:
80         OilIntensity(OilEffect *plugin, int x, int y);
81         int handle_event();
82         OilEffect *plugin;
83 };
84
85 class OilReset : public BC_GenericButton
86 {
87 public:
88         OilReset(OilEffect *plugin, OilWindow *window, int x, int y);
89         ~OilReset();
90         int handle_event();
91         OilEffect *plugin;
92         OilWindow *window;
93 };
94
95
96 class OilWindow : public PluginClientWindow
97 {
98 public:
99         OilWindow(OilEffect *plugin);
100         ~OilWindow();
101         void create_objects();
102         void update();
103         OilEffect *plugin;
104         OilRadius *radius;
105         OilIntensity *intensity;
106         OilReset *reset;
107 };
108
109
110
111
112
113
114
115 class OilServer : public LoadServer
116 {
117 public:
118         OilServer(OilEffect *plugin, int cpus);
119         void init_packages();
120         LoadClient* new_client();
121         LoadPackage* new_package();
122         OilEffect *plugin;
123 };
124
125 class OilPackage : public LoadPackage
126 {
127 public:
128         OilPackage();
129         int row1, row2;
130 };
131
132 class OilUnit : public LoadClient
133 {
134 public:
135         OilUnit(OilEffect *plugin, OilServer *server);
136         void process_package(LoadPackage *package);
137         OilEffect *plugin;
138 };
139
140
141
142
143
144
145
146
147
148 class OilEffect : public PluginVClient
149 {
150 public:
151         OilEffect(PluginServer *server);
152         ~OilEffect();
153
154         PLUGIN_CLASS_MEMBERS(OilConfig);
155         int process_realtime(VFrame *input, VFrame *output);
156         int is_realtime();
157         void save_data(KeyFrame *keyframe);
158         void read_data(KeyFrame *keyframe);
159         void update_gui();
160
161         VFrame *temp_frame;
162         VFrame *input, *output;
163         OilServer *engine;
164         int need_reconfigure;
165 };
166
167
168
169
170
171
172
173
174
175
176
177 OilConfig::OilConfig()
178 {
179         reset();
180 }
181
182 void OilConfig::reset()
183 {
184         radius = 5;
185         use_intensity = 0;
186 }
187
188 void OilConfig::copy_from(OilConfig &src)
189 {
190         this->radius = src.radius;
191         this->use_intensity = src.use_intensity;
192 }
193
194 int OilConfig::equivalent(OilConfig &src)
195 {
196         return (EQUIV(this->radius, src.radius) &&
197                 this->use_intensity == src.use_intensity);
198 }
199
200 void OilConfig::interpolate(OilConfig &prev,
201                 OilConfig &next,
202                 long prev_frame,
203                 long next_frame,
204                 long current_frame)
205 {
206         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
207         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
208         this->radius = prev.radius * prev_scale + next.radius * next_scale;
209         this->use_intensity = prev.use_intensity;
210 // printf("OilConfig::interpolate prev_frame=%ld current_frame=%ld next_frame=%ld prev.radius=%f this->radius=%f next.radius=%f\n",
211 //      prev_frame, current_frame, next_frame, prev.radius, this->radius, next.radius);
212 }
213
214
215
216
217
218
219
220
221
222
223
224
225 OilRadius::OilRadius(OilEffect *plugin, int x, int y)
226  : BC_FSlider(x,
227                 y,
228                 0,
229                 200,
230                 200,
231                 (float)0,
232                 (float)30,
233                 plugin->config.radius)
234 {
235         this->plugin = plugin;
236 }
237 int OilRadius::handle_event()
238 {
239         plugin->config.radius = get_value();
240         plugin->send_configure_change();
241         return 1;
242 }
243
244
245
246
247
248
249
250 OilIntensity::OilIntensity(OilEffect *plugin, int x, int y)
251  : BC_CheckBox(x, y, plugin->config.use_intensity, _("Use intensity"))
252 {
253         this->plugin = plugin;
254 }
255 int OilIntensity::handle_event()
256 {
257         plugin->config.use_intensity = get_value();
258         plugin->send_configure_change();
259         return 1;
260 }
261
262
263 OilReset::OilReset(OilEffect *plugin, OilWindow *window, int x, int y)
264  : BC_GenericButton(x, y, _("Reset"))
265 {
266         this->plugin = plugin;
267         this->window = window;
268 }
269 OilReset::~OilReset()
270 {
271 }
272 int OilReset::handle_event()
273 {
274         plugin->config.reset();
275         window->update();
276         plugin->send_configure_change();
277         return 1;
278 }
279
280
281
282
283
284 OilWindow::OilWindow(OilEffect *plugin)
285  : PluginClientWindow(plugin,
286         300,
287         120,
288         300,
289         120,
290         0)
291 {
292         this->plugin = plugin;
293 }
294
295 OilWindow::~OilWindow()
296 {
297 }
298
299 void OilWindow::create_objects()
300 {
301         int x = 10, y = 10;
302         add_subwindow(new BC_Title(x, y, _("Radius:")));
303         add_subwindow(radius = new OilRadius(plugin, x + 70, y));
304         y += 40;
305         add_subwindow(intensity = new OilIntensity(plugin, x, y));
306         y += 40;
307         add_subwindow(reset = new OilReset(plugin, this, x, y));
308
309         show_window();
310         flush();
311 }
312
313
314 // for Reset button
315 void OilWindow::update()
316 {
317         radius->update(plugin->config.radius);
318         intensity->update(plugin->config.use_intensity);
319 }
320
321
322
323
324
325
326
327 REGISTER_PLUGIN(OilEffect)
328
329
330
331
332 OilEffect::OilEffect(PluginServer *server)
333  : PluginVClient(server)
334 {
335         temp_frame = 0;
336         need_reconfigure = 1;
337         engine = 0;
338
339 }
340
341 OilEffect::~OilEffect()
342 {
343
344
345         if(temp_frame) delete temp_frame;
346         if(engine) delete engine;
347 }
348
349
350 const char* OilEffect::plugin_title() { return N_("Oil painting"); }
351 int OilEffect::is_realtime() { return 1; }
352
353
354
355 NEW_WINDOW_MACRO(OilEffect, OilWindow)
356
357 void OilEffect::update_gui()
358 {
359         if(thread)
360         {
361                 thread->window->lock_window();
362                 load_configuration();
363 //printf("OilEffect::update_gui 1 %ld %f\n", get_source_position(), config.radius);
364
365                 ((OilWindow*)thread->window)->radius->update(config.radius);
366                 ((OilWindow*)thread->window)->intensity->update(config.use_intensity);
367                 thread->window->unlock_window();
368         }
369 }
370
371
372 LOAD_CONFIGURATION_MACRO(OilEffect, OilConfig)
373
374
375 void OilEffect::save_data(KeyFrame *keyframe)
376 {
377         FileXML output;
378
379 // cause data to be stored directly in text
380         output.set_shared_output(keyframe->xbuf);
381         output.tag.set_title("OIL_PAINTING");
382         output.tag.set_property("RADIUS", config.radius);
383         output.tag.set_property("USE_INTENSITY", config.use_intensity);
384         output.append_tag();
385         output.tag.set_title("/OIL_PAINTING");
386         output.append_tag();
387         output.append_newline();
388         output.terminate_string();
389 }
390
391 void OilEffect::read_data(KeyFrame *keyframe)
392 {
393         FileXML input;
394
395         input.set_shared_input(keyframe->xbuf);
396
397         while(!input.read_tag())
398         {
399                 if(input.tag.title_is("OIL_PAINTING"))
400                 {
401                         config.radius = input.tag.get_property("RADIUS", config.radius);
402                         config.use_intensity = input.tag.get_property("USE_INTENSITY", config.use_intensity);
403                 }
404         }
405 }
406
407
408 int OilEffect::process_realtime(VFrame *input, VFrame *output)
409 {
410         need_reconfigure |= load_configuration();
411
412
413
414 //printf("OilEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
415         this->input = input;
416         this->output = output;
417
418         if(EQUIV(config.radius, 0))
419         {
420                 if(input->get_rows()[0] != output->get_rows()[0])
421                         output->copy_from(input);
422         }
423         else
424         {
425                 if(input->get_rows()[0] == output->get_rows()[0])
426                 {
427                         if(!temp_frame)
428                                 temp_frame = new VFrame(input->get_w(), input->get_h(),
429                                         input->get_color_model(), 0);
430                         temp_frame->copy_from(input);
431                         this->input = temp_frame;
432                 }
433
434
435                 if(!engine)
436                 {
437                         engine = new OilServer(this, (PluginClient::smp + 1));
438                 }
439
440                 engine->process_packages();
441         }
442
443
444
445         return 0;
446 }
447
448
449
450
451
452
453 OilPackage::OilPackage()
454  : LoadPackage()
455 {
456 }
457
458
459
460
461
462
463 OilUnit::OilUnit(OilEffect *plugin, OilServer *server)
464  : LoadClient(server)
465 {
466         this->plugin = plugin;
467 }
468
469
470 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
471                                                                         ((p)[1] * 150) + \
472                                                                         ((p)[2] * 29)) >> 8)
473
474
475 #define OIL_MACRO(type, hist_size, components) \
476 { \
477         type *src, *dest; \
478         type val[components]; \
479         int count[components], count2; \
480         int *hist[components]; \
481         int *hist2; \
482         type **src_rows = (type**)plugin->input->get_rows(); \
483  \
484         for(int i = 0; i < components; i++) \
485                 hist[i] = new int[hist_size + 1]; \
486         hist2 = new int[hist_size + 1]; \
487  \
488         for(int y1 = pkg->row1; y1 < pkg->row2; y1++) \
489         { \
490                 dest = (type*)plugin->output->get_rows()[y1]; \
491  \
492                 if(!plugin->config.use_intensity) \
493                 { \
494                         for(int x1 = 0; x1 < w; x1++) \
495                         { \
496                                 bzero(count, sizeof(count)); \
497                                 bzero(val, sizeof(val)); \
498                                 bzero(hist[0], sizeof(int) * (hist_size + 1)); \
499                                 bzero(hist[1], sizeof(int) * (hist_size + 1)); \
500                                 bzero(hist[2], sizeof(int) * (hist_size + 1)); \
501                                 if (components == 4) bzero(hist[3], sizeof(int) * (hist_size + 1)); \
502  \
503                                 int x3 = CLIP((x1 - n), 0, w - 1); \
504                                 int y3 = CLIP((y1 - n), 0, h - 1); \
505                                 int x4 = CLIP((x1 + n + 1), 0, w - 1); \
506                                 int y4 = CLIP((y1 + n + 1), 0, h - 1); \
507  \
508                                 for(int y2 = y3; y2 < y4; y2++) \
509                                 { \
510                                         src = src_rows[y2]; \
511                                         for(int x2 = x3; x2 < x4; x2++) \
512                                         { \
513                                                 int c; \
514                                                 int subscript; \
515                                                 type value; \
516  \
517                         value = src[x2 * components + 0]; \
518                                                 if(sizeof(type) == 4) \
519                                                 { \
520                                                         subscript = (int)(value * hist_size); \
521                                                         CLAMP(subscript, 0, hist_size); \
522                                                 } \
523                                                 else \
524                                                         subscript = (int)value; \
525  \
526                                                 if((c = ++hist[0][subscript]) > count[0]) \
527                                                 { \
528                                                         val[0] = value; \
529                                                         count[0] = c; \
530                                                 } \
531  \
532                         value = src[x2 * components + 1]; \
533                                                 if(sizeof(type) == 4) \
534                                                 { \
535                                                         subscript = (int)(value * hist_size); \
536                                                         CLAMP(subscript, 0, hist_size); \
537                                                 } \
538                                                 else \
539                                                         subscript = (int)value; \
540  \
541                                                 if((c = ++hist[1][subscript]) > count[1]) \
542                                                 { \
543                                                         val[1] = value; \
544                                                         count[1] = c; \
545                                                 } \
546  \
547                         value = src[x2 * components + 2]; \
548                                                 if(sizeof(type) == 4) \
549                                                 { \
550                                                         subscript = (int)(value * hist_size); \
551                                                         CLAMP(subscript, 0, hist_size); \
552                                                 } \
553                                                 else \
554                                                         subscript = (int)value; \
555  \
556                                                 if((c = ++hist[2][subscript]) > count[2]) \
557                                                 { \
558                                                         val[2] = value; \
559                                                         count[2] = c; \
560                                                 } \
561  \
562                                                 if(components == 4) \
563                                                 { \
564                                 value = src[x2 * components + 3]; \
565                                                         if(sizeof(type) == 4) \
566                                                         { \
567                                                                 subscript = (int)(value * hist_size); \
568                                                                 CLAMP(subscript, 0, hist_size); \
569                                                         } \
570                                                         else \
571                                                                 subscript = (int)value; \
572  \
573                                                         if((c = ++hist[3][subscript]) > count[3]) \
574                                                         { \
575                                                                 val[3] = value; \
576                                                                 count[3] = c; \
577                                                         } \
578                                                 } \
579                                         } \
580                                 } \
581  \
582                                 dest[x1 * components + 0] = val[0]; \
583                                 dest[x1 * components + 1] = val[1]; \
584                                 dest[x1 * components + 2] = val[2]; \
585                                 if(components == 4) dest[x1 * components + 3] = val[3]; \
586                         } \
587                 } \
588                 else \
589                 { \
590                         for(int x1 = 0; x1 < w; x1++) \
591                         { \
592                                 count2 = 0; \
593                                 bzero(val, sizeof(val)); \
594                                 bzero(hist2, sizeof(int) * (hist_size + 1)); \
595  \
596                                 int x3 = CLIP((x1 - n), 0, w - 1); \
597                         int y3 = CLIP((y1 - n), 0, h - 1); \
598                         int x4 = CLIP((x1 + n + 1), 0, w - 1); \
599                         int y4 = CLIP((y1 + n + 1), 0, h - 1); \
600  \
601                                 for(int y2 = y3; y2 < y4; y2++) \
602                                 { \
603                                         src = src_rows[y2]; \
604                                         for(int x2 = x3; x2 < x4; x2++) \
605                                         { \
606                                                 int c; \
607                                                 if((c = ++hist2[INTENSITY(src + x2 * components)]) > count2) \
608                                                 { \
609                                                         val[0] = src[x2 * components + 0]; \
610                                                         val[1] = src[x2 * components + 1]; \
611                                                         val[2] = src[x2 * components + 2]; \
612                                                         if(components == 4) val[3] = src[x2 * components + 3]; \
613                                                         count2 = c; \
614                                                 } \
615                                         } \
616                                 } \
617  \
618                                 dest[x1 * components + 0] = val[0]; \
619                                 dest[x1 * components + 1] = val[1]; \
620                                 dest[x1 * components + 2] = val[2]; \
621                                 if(components == 4) dest[x1 * components + 3] = val[3]; \
622                         } \
623                 } \
624         } \
625  \
626         for(int i = 0; i < components; i++) \
627                 delete [] hist[i]; \
628         delete [] hist2; \
629 }
630
631
632
633
634 void OilUnit::process_package(LoadPackage *package)
635 {
636         OilPackage *pkg = (OilPackage*)package;
637         int w = plugin->input->get_w();
638         int h = plugin->input->get_h();
639         int n = (int)(plugin->config.radius / 2);
640
641         switch(plugin->input->get_color_model())
642         {
643                 case BC_RGB_FLOAT:
644                         OIL_MACRO(float, 0xffff, 3)
645                         break;
646                 case BC_RGB888:
647                 case BC_YUV888:
648                         OIL_MACRO(unsigned char, 0xff, 3)
649                         break;
650                 case BC_RGB161616:
651                 case BC_YUV161616:
652                         OIL_MACRO(uint16_t, 0xffff, 3)
653                         break;
654                 case BC_RGBA_FLOAT:
655                         OIL_MACRO(float, 0xffff, 4)
656                         break;
657                 case BC_RGBA8888:
658                 case BC_YUVA8888:
659                         OIL_MACRO(unsigned char, 0xff, 4)
660                         break;
661                 case BC_RGBA16161616:
662                 case BC_YUVA16161616:
663                         OIL_MACRO(uint16_t, 0xffff, 4)
664                         break;
665         }
666
667
668
669
670 }
671
672
673
674
675
676
677 OilServer::OilServer(OilEffect *plugin, int cpus)
678  : LoadServer(cpus, cpus)
679 {
680         this->plugin = plugin;
681 }
682
683 void OilServer::init_packages()
684 {
685         for(int i = 0; i < LoadServer::get_total_packages(); i++)
686         {
687                 OilPackage *pkg = (OilPackage*)get_package(i);
688                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
689                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
690         }
691 }
692
693
694 LoadClient* OilServer::new_client()
695 {
696         return new OilUnit(plugin, this);
697 }
698
699 LoadPackage* OilServer::new_package()
700 {
701         return new OilPackage;
702 }
703