1 #include "bcdisplayinfo.h"
8 #include "loadbalance.h"
10 #include "pluginvclient.h"
20 // Algorithm by Torsten Martinsen
21 // Ported to Cinelerra by Heroine Virtual Ltd.
34 void copy_from(OilConfig &src);
35 int equivalent(OilConfig &src);
36 void interpolate(OilConfig &prev,
45 class OilRadius : public BC_FSlider
48 OilRadius(OilEffect *plugin, int x, int y);
54 class OilIntensity : public BC_CheckBox
57 OilIntensity(OilEffect *plugin, int x, int y);
62 class OilWindow : public BC_Window
65 OilWindow(OilEffect *plugin, int x, int y);
67 void create_objects();
71 OilIntensity *intensity;
74 PLUGIN_THREAD_HEADER(OilEffect, OilThread, OilWindow)
80 class OilServer : public LoadServer
83 OilServer(OilEffect *plugin, int cpus);
85 LoadClient* new_client();
86 LoadPackage* new_package();
90 class OilPackage : public LoadPackage
97 class OilUnit : public LoadClient
100 OilUnit(OilEffect *plugin, OilServer *server);
101 void process_package(LoadPackage *package);
113 class OilEffect : public PluginVClient
116 OilEffect(PluginServer *server);
119 int process_realtime(VFrame *input, VFrame *output);
121 char* plugin_title();
123 int load_configuration();
126 void save_data(KeyFrame *keyframe);
127 void read_data(KeyFrame *keyframe);
135 VFrame *input, *output;
139 int need_reconfigure;
154 OilConfig::OilConfig()
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,
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)
205 plugin->config.radius)
207 this->plugin = plugin;
209 int OilRadius::handle_event()
211 plugin->config.radius = get_value();
212 plugin->send_configure_change();
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();
240 OilWindow::OilWindow(OilEffect *plugin, int x, int y)
241 : BC_Window(plugin->gui_string,
252 this->plugin = plugin;
255 OilWindow::~OilWindow()
259 void OilWindow::create_objects()
262 add_subwindow(new BC_Title(x, y, _("Radius:")));
263 add_subwindow(radius = new OilRadius(plugin, x + 70, y));
265 add_subwindow(intensity = new OilIntensity(plugin, x, y));
271 WINDOW_CLOSE_EVENT(OilWindow)
275 PLUGIN_THREAD_OBJECT(OilEffect, OilThread, OilWindow)
280 REGISTER_PLUGIN(OilEffect)
285 OilEffect::OilEffect(PluginServer *server)
286 : PluginVClient(server)
289 need_reconfigure = 1;
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()
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();
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);
339 defaults = new Defaults(directory);
342 config.radius = defaults->get("RADIUS", config.radius);
343 config.use_intensity = defaults->get("USE_INTENSITY", config.use_intensity);
347 int OilEffect::save_defaults()
349 defaults->update("RADIUS", config.radius);
350 defaults->update("USE_INTENSITY", config.use_intensity);
355 void OilEffect::save_data(KeyFrame *keyframe)
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);
365 output.terminate_string();
368 void OilEffect::read_data(KeyFrame *keyframe)
372 input.set_shared_string(keyframe->data, strlen(keyframe->data));
376 while(!input.read_tag())
378 if(input.tag.title_is("OIL_PAINTING"))
380 config.radius = input.tag.get_property("RADIUS", config.radius);
381 config.use_intensity = input.tag.get_property("USE_INTENSITY", config.use_intensity);
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);
395 this->output = output;
397 if(EQUIV(config.radius, 0))
399 if(input->get_rows()[0] != output->get_rows()[0])
400 output->copy_from(input);
404 if(input->get_rows()[0] == output->get_rows()[0])
406 if(!temp_frame) temp_frame = new VFrame(0,
409 input->get_color_model());
410 temp_frame->copy_from(input);
411 this->input = temp_frame;
417 engine = new OilServer(this, (PluginClient::smp + 1));
420 engine->process_packages();
433 OilPackage::OilPackage()
443 OilUnit::OilUnit(OilEffect *plugin, OilServer *server)
446 this->plugin = plugin;
450 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
455 #define OIL_MACRO(type, hist_size, components) \
458 type val[components]; \
459 int count[components], count2; \
460 int *hist[components]; \
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]; \
469 for(int y1 = pkg->row1; y1 < pkg->row2; y1++) \
471 dest = (type*)plugin->output->get_rows()[y1]; \
473 printf("2 %d\n", y1); \
474 if(!plugin->config.use_intensity) \
476 for(int x1 = 0; x1 < w; x1++) \
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++) \
491 src = src_rows[y2]; \
492 for(int x2 = x3; x2 < x4; x2++) \
498 value = src[x2 * components + 0]; \
499 if(sizeof(type) == 4) \
501 subscript = (int)(value * hist_size); \
502 CLAMP(subscript, 0, hist_size); \
505 subscript = (int)value; \
507 if((c = ++hist[0][subscript]) > count[0]) \
513 value = src[x2 * components + 1]; \
514 if(sizeof(type) == 4) \
516 subscript = (int)(value * hist_size); \
517 CLAMP(subscript, 0, hist_size); \
520 subscript = (int)value; \
522 if((c = ++hist[1][subscript]) > count[1]) \
528 value = src[x2 * components + 2]; \
529 if(sizeof(type) == 4) \
531 subscript = (int)(value * hist_size); \
532 CLAMP(subscript, 0, hist_size); \
535 subscript = (int)value; \
537 if((c = ++hist[2][subscript]) > count[2]) \
543 if(components == 4) \
545 value = src[x2 * components + 3]; \
546 if(sizeof(type) == 4) \
548 subscript = (int)(value * hist_size); \
549 CLAMP(subscript, 0, hist_size); \
552 subscript = (int)value; \
554 if((c = ++hist[3][subscript]) > count[3]) \
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]; \
571 for(int x1 = 0; x1 < w; x1++) \
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++) \
584 src = src_rows[y2]; \
585 for(int x2 = x3; x2 < x4; x2++) \
588 if((c = ++hist2[INTENSITY(src + x2 * components)]) > count2) \
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]; \
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]; \
607 for(int i = 0; i < components; i++) \
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())
626 OIL_MACRO(float, 0xffff, 3)
630 OIL_MACRO(unsigned char, 0xff, 3)
634 OIL_MACRO(uint16_t, 0xffff, 3)
637 OIL_MACRO(float, 0xffff, 4)
641 OIL_MACRO(unsigned char, 0xff, 4)
643 case BC_RGBA16161616:
644 case BC_YUVA16161616:
645 OIL_MACRO(uint16_t, 0xffff, 4)
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;
669 for(int i = 0; i < LoadServer::total_packages; i++)
671 OilPackage *pkg = (OilPackage*)packages[i];
673 pkg->row2 = y + increment;
675 if(pkg->row2 > plugin->input->get_h())
677 y = pkg->row2 = plugin->input->get_h();
683 LoadClient* OilServer::new_client()
685 return new OilUnit(plugin, this);
688 LoadPackage* OilServer::new_package()
690 return new OilPackage;