00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "guicast.h"
00006 #include "keyframe.h"
00007 #include "language.h"
00008 #include "loadbalance.h"
00009 #include "picon_png.h"
00010 #include "pluginvclient.h"
00011 #include "vframe.h"
00012
00013 #include <math.h>
00014 #include <stdint.h>
00015 #include <string.h>
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 class OilEffect;
00027
00028
00029
00030 class OilConfig
00031 {
00032 public:
00033 OilConfig();
00034 void copy_from(OilConfig &src);
00035 int equivalent(OilConfig &src);
00036 void interpolate(OilConfig &prev,
00037 OilConfig &next,
00038 long prev_frame,
00039 long next_frame,
00040 long current_frame);
00041 float radius;
00042 int use_intensity;
00043 };
00044
00045 class OilRadius : public BC_FSlider
00046 {
00047 public:
00048 OilRadius(OilEffect *plugin, int x, int y);
00049 int handle_event();
00050 OilEffect *plugin;
00051 };
00052
00053
00054 class OilIntensity : public BC_CheckBox
00055 {
00056 public:
00057 OilIntensity(OilEffect *plugin, int x, int y);
00058 int handle_event();
00059 OilEffect *plugin;
00060 };
00061
00062 class OilWindow : public BC_Window
00063 {
00064 public:
00065 OilWindow(OilEffect *plugin, int x, int y);
00066 ~OilWindow();
00067 void create_objects();
00068 int close_event();
00069 OilEffect *plugin;
00070 OilRadius *radius;
00071 OilIntensity *intensity;
00072 };
00073
00074 PLUGIN_THREAD_HEADER(OilEffect, OilThread, OilWindow)
00075
00076
00077
00078
00079
00080 class OilServer : public LoadServer
00081 {
00082 public:
00083 OilServer(OilEffect *plugin, int cpus);
00084 void init_packages();
00085 LoadClient* new_client();
00086 LoadPackage* new_package();
00087 OilEffect *plugin;
00088 };
00089
00090 class OilPackage : public LoadPackage
00091 {
00092 public:
00093 OilPackage();
00094 int row1, row2;
00095 };
00096
00097 class OilUnit : public LoadClient
00098 {
00099 public:
00100 OilUnit(OilEffect *plugin, OilServer *server);
00101 void process_package(LoadPackage *package);
00102 OilEffect *plugin;
00103 };
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 class OilEffect : public PluginVClient
00114 {
00115 public:
00116 OilEffect(PluginServer *server);
00117 ~OilEffect();
00118
00119 int process_realtime(VFrame *input, VFrame *output);
00120 int is_realtime();
00121 char* plugin_title();
00122 VFrame* new_picon();
00123 int load_configuration();
00124 int load_defaults();
00125 int save_defaults();
00126 void save_data(KeyFrame *keyframe);
00127 void read_data(KeyFrame *keyframe);
00128 int show_gui();
00129 int set_string();
00130 void raise_window();
00131 void update_gui();
00132
00133 OilConfig config;
00134 VFrame *temp_frame;
00135 VFrame *input, *output;
00136 BC_Hash *defaults;
00137 OilThread *thread;
00138 OilServer *engine;
00139 int need_reconfigure;
00140 };
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 OilConfig::OilConfig()
00155 {
00156 radius = 5;
00157 use_intensity = 0;
00158 }
00159
00160 void OilConfig::copy_from(OilConfig &src)
00161 {
00162 this->radius = src.radius;
00163 this->use_intensity = src.use_intensity;
00164 }
00165
00166 int OilConfig::equivalent(OilConfig &src)
00167 {
00168 return (EQUIV(this->radius, src.radius) &&
00169 this->use_intensity == src.use_intensity);
00170 }
00171
00172 void OilConfig::interpolate(OilConfig &prev,
00173 OilConfig &next,
00174 long prev_frame,
00175 long next_frame,
00176 long current_frame)
00177 {
00178 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00179 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00180 this->radius = prev.radius * prev_scale + next.radius * next_scale;
00181 this->use_intensity = prev.use_intensity;
00182
00183
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 OilRadius::OilRadius(OilEffect *plugin, int x, int y)
00198 : BC_FSlider(x,
00199 y,
00200 0,
00201 200,
00202 200,
00203 (float)0,
00204 (float)30,
00205 plugin->config.radius)
00206 {
00207 this->plugin = plugin;
00208 }
00209 int OilRadius::handle_event()
00210 {
00211 plugin->config.radius = get_value();
00212 plugin->send_configure_change();
00213 return 1;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 OilIntensity::OilIntensity(OilEffect *plugin, int x, int y)
00223 : BC_CheckBox(x, y, plugin->config.use_intensity, _("Use intensity"))
00224 {
00225 this->plugin = plugin;
00226 }
00227 int OilIntensity::handle_event()
00228 {
00229 plugin->config.use_intensity = get_value();
00230 plugin->send_configure_change();
00231 return 1;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240 OilWindow::OilWindow(OilEffect *plugin, int x, int y)
00241 : BC_Window(plugin->gui_string,
00242 x,
00243 y,
00244 300,
00245 160,
00246 300,
00247 160,
00248 0,
00249 0,
00250 1)
00251 {
00252 this->plugin = plugin;
00253 }
00254
00255 OilWindow::~OilWindow()
00256 {
00257 }
00258
00259 void OilWindow::create_objects()
00260 {
00261 int x = 10, y = 10;
00262 add_subwindow(new BC_Title(x, y, _("Radius:")));
00263 add_subwindow(radius = new OilRadius(plugin, x + 70, y));
00264 y += 40;
00265 add_subwindow(intensity = new OilIntensity(plugin, x, y));
00266
00267 show_window();
00268 flush();
00269 }
00270
00271 WINDOW_CLOSE_EVENT(OilWindow)
00272
00273
00274
00275 PLUGIN_THREAD_OBJECT(OilEffect, OilThread, OilWindow)
00276
00277
00278
00279
00280 REGISTER_PLUGIN(OilEffect)
00281
00282
00283
00284
00285 OilEffect::OilEffect(PluginServer *server)
00286 : PluginVClient(server)
00287 {
00288 temp_frame = 0;
00289 need_reconfigure = 1;
00290 engine = 0;
00291 PLUGIN_CONSTRUCTOR_MACRO
00292 }
00293
00294 OilEffect::~OilEffect()
00295 {
00296 PLUGIN_DESTRUCTOR_MACRO
00297
00298 if(temp_frame) delete temp_frame;
00299 if(engine) delete engine;
00300 }
00301
00302
00303 char* OilEffect::plugin_title() { return N_("Oil painting"); }
00304 int OilEffect::is_realtime() { return 1; }
00305
00306
00307 NEW_PICON_MACRO(OilEffect)
00308
00309 SHOW_GUI_MACRO(OilEffect, OilThread)
00310
00311 RAISE_WINDOW_MACRO(OilEffect)
00312
00313 SET_STRING_MACRO(OilEffect)
00314
00315 void OilEffect::update_gui()
00316 {
00317 if(thread)
00318 {
00319 thread->window->lock_window();
00320 load_configuration();
00321
00322
00323 thread->window->radius->update(config.radius);
00324 thread->window->intensity->update(config.use_intensity);
00325 thread->window->unlock_window();
00326 }
00327 }
00328
00329
00330 LOAD_CONFIGURATION_MACRO(OilEffect, OilConfig)
00331
00332 int OilEffect::load_defaults()
00333 {
00334 char directory[BCTEXTLEN];
00335
00336 sprintf(directory, "%soilpainting.rc", BCASTDIR);
00337
00338
00339 defaults = new BC_Hash(directory);
00340 defaults->load();
00341
00342 config.radius = defaults->get("RADIUS", config.radius);
00343 config.use_intensity = defaults->get("USE_INTENSITY", config.use_intensity);
00344 return 0;
00345 }
00346
00347 int OilEffect::save_defaults()
00348 {
00349 defaults->update("RADIUS", config.radius);
00350 defaults->update("USE_INTENSITY", config.use_intensity);
00351 defaults->save();
00352 return 0;
00353 }
00354
00355 void OilEffect::save_data(KeyFrame *keyframe)
00356 {
00357 FileXML output;
00358
00359
00360 output.set_shared_string(keyframe->data, MESSAGESIZE);
00361 output.tag.set_title("OIL_PAINTING");
00362 output.tag.set_property("RADIUS", config.radius);
00363 output.tag.set_property("USE_INTENSITY", config.use_intensity);
00364 output.append_tag();
00365 output.tag.set_title("/OIL_PAINTING");
00366 output.append_tag();
00367 output.terminate_string();
00368 }
00369
00370 void OilEffect::read_data(KeyFrame *keyframe)
00371 {
00372 FileXML input;
00373
00374 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00375
00376 int result = 0;
00377
00378 while(!input.read_tag())
00379 {
00380 if(input.tag.title_is("OIL_PAINTING"))
00381 {
00382 config.radius = input.tag.get_property("RADIUS", config.radius);
00383 config.use_intensity = input.tag.get_property("USE_INTENSITY", config.use_intensity);
00384 }
00385 }
00386 }
00387
00388
00389 int OilEffect::process_realtime(VFrame *input, VFrame *output)
00390 {
00391 need_reconfigure |= load_configuration();
00392
00393
00394
00395
00396 this->input = input;
00397 this->output = output;
00398
00399 if(EQUIV(config.radius, 0))
00400 {
00401 if(input->get_rows()[0] != output->get_rows()[0])
00402 output->copy_from(input);
00403 }
00404 else
00405 {
00406 if(input->get_rows()[0] == output->get_rows()[0])
00407 {
00408 if(!temp_frame) temp_frame = new VFrame(0,
00409 input->get_w(),
00410 input->get_h(),
00411 input->get_color_model());
00412 temp_frame->copy_from(input);
00413 this->input = temp_frame;
00414 }
00415
00416
00417 if(!engine)
00418 {
00419 engine = new OilServer(this, (PluginClient::smp + 1));
00420 }
00421
00422 engine->process_packages();
00423 }
00424
00425
00426
00427 return 0;
00428 }
00429
00430
00431
00432
00433
00434
00435 OilPackage::OilPackage()
00436 : LoadPackage()
00437 {
00438 }
00439
00440
00441
00442
00443
00444
00445 OilUnit::OilUnit(OilEffect *plugin, OilServer *server)
00446 : LoadClient(server)
00447 {
00448 this->plugin = plugin;
00449 }
00450
00451
00452 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
00453 ((p)[1] * 150) + \
00454 ((p)[2] * 29)) >> 8)
00455
00456
00457 #define OIL_MACRO(type, hist_size, components) \
00458 { \
00459 type *src, *dest; \
00460 type val[components]; \
00461 int count[components], count2; \
00462 int *hist[components]; \
00463 int *hist2; \
00464 type **src_rows = (type**)plugin->input->get_rows(); \
00465 \
00466 for(int i = 0; i < components; i++) \
00467 hist[i] = new int[hist_size + 1]; \
00468 hist2 = new int[hist_size + 1]; \
00469 \
00470 for(int y1 = pkg->row1; y1 < pkg->row2; y1++) \
00471 { \
00472 dest = (type*)plugin->output->get_rows()[y1]; \
00473 \
00474 if(!plugin->config.use_intensity) \
00475 { \
00476 for(int x1 = 0; x1 < w; x1++) \
00477 { \
00478 bzero(count, sizeof(count)); \
00479 bzero(val, sizeof(val)); \
00480 bzero(hist[0], sizeof(int) * (hist_size + 1)); \
00481 bzero(hist[1], sizeof(int) * (hist_size + 1)); \
00482 bzero(hist[2], sizeof(int) * (hist_size + 1)); \
00483 if (components == 4) bzero(hist[3], sizeof(int) * (hist_size + 1)); \
00484 \
00485 int x3 = CLIP((x1 - n), 0, w - 1); \
00486 int y3 = CLIP((y1 - n), 0, h - 1); \
00487 int x4 = CLIP((x1 + n + 1), 0, w - 1); \
00488 int y4 = CLIP((y1 + n + 1), 0, h - 1); \
00489 \
00490 for(int y2 = y3; y2 < y4; y2++) \
00491 { \
00492 src = src_rows[y2]; \
00493 for(int x2 = x3; x2 < x4; x2++) \
00494 { \
00495 int c; \
00496 int subscript; \
00497 type value; \
00498 \
00499 value = src[x2 * components + 0]; \
00500 if(sizeof(type) == 4) \
00501 { \
00502 subscript = (int)(value * hist_size); \
00503 CLAMP(subscript, 0, hist_size); \
00504 } \
00505 else \
00506 subscript = (int)value; \
00507 \
00508 if((c = ++hist[0][subscript]) > count[0]) \
00509 { \
00510 val[0] = value; \
00511 count[0] = c; \
00512 } \
00513 \
00514 value = src[x2 * components + 1]; \
00515 if(sizeof(type) == 4) \
00516 { \
00517 subscript = (int)(value * hist_size); \
00518 CLAMP(subscript, 0, hist_size); \
00519 } \
00520 else \
00521 subscript = (int)value; \
00522 \
00523 if((c = ++hist[1][subscript]) > count[1]) \
00524 { \
00525 val[1] = value; \
00526 count[1] = c; \
00527 } \
00528 \
00529 value = src[x2 * components + 2]; \
00530 if(sizeof(type) == 4) \
00531 { \
00532 subscript = (int)(value * hist_size); \
00533 CLAMP(subscript, 0, hist_size); \
00534 } \
00535 else \
00536 subscript = (int)value; \
00537 \
00538 if((c = ++hist[2][subscript]) > count[2]) \
00539 { \
00540 val[2] = value; \
00541 count[2] = c; \
00542 } \
00543 \
00544 if(components == 4) \
00545 { \
00546 value = src[x2 * components + 3]; \
00547 if(sizeof(type) == 4) \
00548 { \
00549 subscript = (int)(value * hist_size); \
00550 CLAMP(subscript, 0, hist_size); \
00551 } \
00552 else \
00553 subscript = (int)value; \
00554 \
00555 if((c = ++hist[3][subscript]) > count[3]) \
00556 { \
00557 val[3] = value; \
00558 count[3] = c; \
00559 } \
00560 } \
00561 } \
00562 } \
00563 \
00564 dest[x1 * components + 0] = val[0]; \
00565 dest[x1 * components + 1] = val[1]; \
00566 dest[x1 * components + 2] = val[2]; \
00567 if(components == 4) dest[x1 * components + 3] = val[3]; \
00568 } \
00569 } \
00570 else \
00571 { \
00572 for(int x1 = 0; x1 < w; x1++) \
00573 { \
00574 count2 = 0; \
00575 bzero(val, sizeof(val)); \
00576 bzero(hist2, sizeof(int) * (hist_size + 1)); \
00577 \
00578 int x3 = CLIP((x1 - n), 0, w - 1); \
00579 int y3 = CLIP((y1 - n), 0, h - 1); \
00580 int x4 = CLIP((x1 + n + 1), 0, w - 1); \
00581 int y4 = CLIP((y1 + n + 1), 0, h - 1); \
00582 \
00583 for(int y2 = y3; y2 < y4; y2++) \
00584 { \
00585 src = src_rows[y2]; \
00586 for(int x2 = x3; x2 < x4; x2++) \
00587 { \
00588 int c; \
00589 if((c = ++hist2[INTENSITY(src + x2 * components)]) > count2) \
00590 { \
00591 val[0] = src[x2 * components + 0]; \
00592 val[1] = src[x2 * components + 1]; \
00593 val[2] = src[x2 * components + 2]; \
00594 if(components == 4) val[3] = src[x2 * components + 3]; \
00595 count2 = c; \
00596 } \
00597 } \
00598 } \
00599 \
00600 dest[x1 * components + 0] = val[0]; \
00601 dest[x1 * components + 1] = val[1]; \
00602 dest[x1 * components + 2] = val[2]; \
00603 if(components == 4) dest[x1 * components + 3] = val[3]; \
00604 } \
00605 } \
00606 } \
00607 \
00608 for(int i = 0; i < components; i++) \
00609 delete [] hist[i]; \
00610 delete [] hist2; \
00611 }
00612
00613
00614
00615
00616 void OilUnit::process_package(LoadPackage *package)
00617 {
00618 OilPackage *pkg = (OilPackage*)package;
00619 int w = plugin->input->get_w();
00620 int h = plugin->input->get_h();
00621 int n = (int)(plugin->config.radius / 2);
00622
00623 switch(plugin->input->get_color_model())
00624 {
00625 case BC_RGB_FLOAT:
00626 OIL_MACRO(float, 0xffff, 3)
00627 break;
00628 case BC_RGB888:
00629 case BC_YUV888:
00630 OIL_MACRO(unsigned char, 0xff, 3)
00631 break;
00632 case BC_RGB161616:
00633 case BC_YUV161616:
00634 OIL_MACRO(uint16_t, 0xffff, 3)
00635 break;
00636 case BC_RGBA_FLOAT:
00637 OIL_MACRO(float, 0xffff, 4)
00638 break;
00639 case BC_RGBA8888:
00640 case BC_YUVA8888:
00641 OIL_MACRO(unsigned char, 0xff, 4)
00642 break;
00643 case BC_RGBA16161616:
00644 case BC_YUVA16161616:
00645 OIL_MACRO(uint16_t, 0xffff, 4)
00646 break;
00647 }
00648
00649
00650
00651
00652 }
00653
00654
00655
00656
00657
00658
00659 OilServer::OilServer(OilEffect *plugin, int cpus)
00660 : LoadServer(cpus, cpus)
00661 {
00662 this->plugin = plugin;
00663 }
00664
00665 void OilServer::init_packages()
00666 {
00667 for(int i = 0; i < LoadServer::get_total_packages(); i++)
00668 {
00669 OilPackage *pkg = (OilPackage*)get_package(i);
00670 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
00671 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
00672 }
00673 }
00674
00675
00676 LoadClient* OilServer::new_client()
00677 {
00678 return new OilUnit(plugin, this);
00679 }
00680
00681 LoadPackage* OilServer::new_package()
00682 {
00683 return new OilPackage;
00684 }
00685