00001 #include "clip.h"
00002 #include "bchash.h"
00003 #include "filexml.h"
00004 #include "histogramengine.h"
00005 #include "language.h"
00006 #include "plugincolors.h"
00007 #include "threshold.h"
00008 #include "thresholdwindow.h"
00009 #include "vframe.h"
00010
00011 #include <string.h>
00012 #include <string>
00013
00014 using std::string;
00015
00016
00017
00018 ThresholdConfig::ThresholdConfig()
00019 {
00020 reset();
00021 }
00022
00023 int ThresholdConfig::equivalent(ThresholdConfig &that)
00024 {
00025 return EQUIV(min, that.min) &&
00026 EQUIV(max, that.max) &&
00027 plot == that.plot &&
00028 low_color == that.low_color &&
00029 mid_color == that.mid_color &&
00030 high_color == that.high_color;
00031 }
00032
00033 void ThresholdConfig::copy_from(ThresholdConfig &that)
00034 {
00035 min = that.min;
00036 max = that.max;
00037 plot = that.plot;
00038 low_color = that.low_color;
00039 mid_color = that.mid_color;
00040 high_color = that.high_color;
00041 }
00042
00043
00044 template<typename T>
00045 T interpolate(const T & prev, const double & prev_scale, const T & next, const double & next_scale)
00046 {
00047 return static_cast<T>(prev * prev_scale + next * next_scale);
00048 }
00049
00050 void ThresholdConfig::interpolate(ThresholdConfig &prev,
00051 ThresholdConfig &next,
00052 int64_t prev_frame,
00053 int64_t next_frame,
00054 int64_t current_frame)
00055 {
00056 double next_scale = (double)(current_frame - prev_frame) /
00057 (next_frame - prev_frame);
00058 double prev_scale = (double)(next_frame - current_frame) /
00059 (next_frame - prev_frame);
00060
00061 min = ::interpolate(prev.min, prev_scale, next.min, next_scale);
00062 max = ::interpolate(prev.max, prev_scale, next.max, next_scale);
00063 plot = prev.plot;
00064
00065 low_color = ::interpolate(prev.low_color, prev_scale, next.low_color, next_scale);
00066 mid_color = ::interpolate(prev.mid_color, prev_scale, next.mid_color, next_scale);
00067 high_color = ::interpolate(prev.high_color, prev_scale, next.high_color, next_scale);
00068 }
00069
00070 void ThresholdConfig::reset()
00071 {
00072 min = 0.0;
00073 max = 1.0;
00074 plot = 1;
00075 low_color.set (0x0, 0x0, 0x0, 0xff);
00076 mid_color.set (0xff, 0xff, 0xff, 0xff);
00077 high_color.set(0x0, 0x0, 0x0, 0xff);
00078 }
00079
00080 void ThresholdConfig::boundaries()
00081 {
00082 CLAMP(min, HISTOGRAM_MIN, max);
00083 CLAMP(max, min, HISTOGRAM_MAX);
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093 REGISTER_PLUGIN(ThresholdMain)
00094
00095 ThresholdMain::ThresholdMain(PluginServer *server)
00096 : PluginVClient(server)
00097 {
00098 PLUGIN_CONSTRUCTOR_MACRO
00099 engine = 0;
00100 threshold_engine = 0;
00101 }
00102
00103 ThresholdMain::~ThresholdMain()
00104 {
00105 PLUGIN_DESTRUCTOR_MACRO
00106 delete engine;
00107 delete threshold_engine;
00108 }
00109
00110 int ThresholdMain::is_realtime()
00111 {
00112 return 1;
00113 }
00114
00115 char* ThresholdMain::plugin_title()
00116 {
00117 return N_("Threshold");
00118 }
00119
00120
00121 #include "picon_png.h"
00122 NEW_PICON_MACRO(ThresholdMain)
00123
00124 SHOW_GUI_MACRO(ThresholdMain, ThresholdThread)
00125
00126 SET_STRING_MACRO(ThresholdMain)
00127
00128 RAISE_WINDOW_MACRO(ThresholdMain)
00129
00130 LOAD_CONFIGURATION_MACRO(ThresholdMain, ThresholdConfig)
00131
00132
00133
00134
00135
00136
00137
00138 int ThresholdMain::process_buffer(VFrame *frame,
00139 int64_t start_position,
00140 double frame_rate)
00141 {
00142 load_configuration();
00143
00144 int use_opengl = get_use_opengl() &&
00145 (!config.plot || !gui_open());
00146
00147 read_frame(frame,
00148 0,
00149 get_source_position(),
00150 get_framerate(),
00151 use_opengl);
00152
00153 if(use_opengl) return run_opengl();
00154
00155 send_render_gui(frame);
00156
00157 if(!threshold_engine)
00158 threshold_engine = new ThresholdEngine(this);
00159 threshold_engine->process_packages(frame);
00160
00161 return 0;
00162 }
00163
00164 int ThresholdMain::load_defaults()
00165 {
00166 char directory[BCTEXTLEN], string[BCTEXTLEN];
00167 sprintf(directory, "%sthreshold.rc", BCASTDIR);
00168 defaults = new BC_Hash(directory);
00169 defaults->load();
00170 config.min = defaults->get("MIN", config.min);
00171 config.max = defaults->get("MAX", config.max);
00172 config.plot = defaults->get("PLOT", config.plot);
00173 config.low_color.load_default(defaults, "LOW_COLOR");
00174 config.mid_color.load_default(defaults, "MID_COLOR");
00175 config.high_color.load_default(defaults, "HIGH_COLOR");
00176 config.boundaries();
00177 return 0;
00178 }
00179
00180 int ThresholdMain::save_defaults()
00181 {
00182 defaults->update("MIN", config.min);
00183 defaults->update("MAX", config.max);
00184 defaults->update("PLOT", config.plot);
00185 config.low_color.save_defaults(defaults, "LOW_COLOR");
00186 config.mid_color.save_defaults(defaults, "MID_COLOR");
00187 config.high_color.save_defaults(defaults, "HIGH_COLOR");
00188 defaults->save();
00189 }
00190
00191 void ThresholdMain::save_data(KeyFrame *keyframe)
00192 {
00193 FileXML file;
00194 file.set_shared_string(keyframe->data, MESSAGESIZE);
00195 file.tag.set_title("THRESHOLD");
00196 file.tag.set_property("MIN", config.min);
00197 file.tag.set_property("MAX", config.max);
00198 file.tag.set_property("PLOT", config.plot);
00199 config.low_color.set_property(file.tag, "LOW_COLOR");
00200 config.mid_color.set_property(file.tag, "MID_COLOR");
00201 config.high_color.set_property(file.tag, "HIGH_COLOR");
00202 file.append_tag();
00203 file.tag.set_title("/THRESHOLD");
00204 file.append_tag();
00205 file.terminate_string();
00206 }
00207
00208 void ThresholdMain::read_data(KeyFrame *keyframe)
00209 {
00210 FileXML file;
00211 file.set_shared_string(keyframe->data, strlen(keyframe->data));
00212 int result = 0;
00213 while(!result)
00214 {
00215 result = file.read_tag();
00216 if(!result)
00217 {
00218 config.min = file.tag.get_property("MIN", config.min);
00219 config.max = file.tag.get_property("MAX", config.max);
00220 config.plot = file.tag.get_property("PLOT", config.plot);
00221 config.low_color = config.low_color.get_property(file.tag, "LOW_COLOR");
00222 config.mid_color = config.mid_color.get_property(file.tag, "MID_COLOR");
00223 config.high_color = config.high_color.get_property(file.tag, "HIGH_COLOR");
00224 }
00225 }
00226 config.boundaries();
00227 }
00228
00229 void ThresholdMain::update_gui()
00230 {
00231 if(thread)
00232 {
00233 thread->window->lock_window("ThresholdMain::update_gui");
00234 if(load_configuration())
00235 {
00236 thread->window->min->update(config.min);
00237 thread->window->max->update(config.max);
00238 thread->window->plot->update(config.plot);
00239 thread->window->update_low_color();
00240 thread->window->update_mid_color();
00241 thread->window->update_high_color();
00242 thread->window->low_color_thread->update_gui(config.low_color.getRGB(), config.low_color.a);
00243 thread->window->mid_color_thread->update_gui(config.mid_color.getRGB(), config.mid_color.a);
00244 thread->window->high_color_thread->update_gui(config.high_color.getRGB(), config.high_color.a);
00245 }
00246 thread->window->unlock_window();
00247 }
00248 }
00249
00250 void ThresholdMain::render_gui(void *data)
00251 {
00252 if(thread)
00253 {
00254 calculate_histogram((VFrame*)data);
00255 thread->window->lock_window("ThresholdMain::render_gui");
00256 thread->window->canvas->draw();
00257 thread->window->unlock_window();
00258 }
00259 }
00260
00261 void ThresholdMain::calculate_histogram(VFrame *frame)
00262 {
00263 if(!engine) engine = new HistogramEngine(get_project_smp() + 1,
00264 get_project_smp() + 1);
00265 engine->process_packages(frame);
00266 }
00267
00268 int ThresholdMain::handle_opengl()
00269 {
00270 #ifdef HAVE_GL
00271 static char *rgb_shader =
00272 "uniform sampler2D tex;\n"
00273 "uniform float min;\n"
00274 "uniform float max;\n"
00275 "uniform vec4 low_color;\n"
00276 "uniform vec4 mid_color;\n"
00277 "uniform vec4 high_color;\n"
00278 "void main()\n"
00279 "{\n"
00280 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
00281 " float v = dot(pixel.rgb, vec3(0.299, 0.587, 0.114));\n"
00282 " if(v < min)\n"
00283 " pixel = low_color;\n"
00284 " else if(v < max)\n"
00285 " pixel = mid_color;\n"
00286 " else\n"
00287 " pixel = high_color;\n"
00288 " gl_FragColor = pixel;\n"
00289 "}\n";
00290
00291 static char *yuv_shader =
00292 "uniform sampler2D tex;\n"
00293 "uniform float min;\n"
00294 "uniform float max;\n"
00295 "uniform vec4 low_color;\n"
00296 "uniform vec4 mid_color;\n"
00297 "uniform vec4 high_color;\n"
00298 "void main()\n"
00299 "{\n"
00300 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
00301 " if(pixel.r < min)\n"
00302 " pixel = low_color;\n"
00303 " else if(pixel.r < max)\n"
00304 " pixel = mid_color;\n"
00305 " else\n"
00306 " pixel = high_color;\n"
00307 " gl_FragColor = pixel;\n"
00308 "}\n";
00309
00310 get_output()->to_texture();
00311 get_output()->enable_opengl();
00312
00313 unsigned int shader = 0;
00314 int color_model = get_output()->get_color_model();
00315 bool is_yuv = cmodel_is_yuv(color_model);
00316 bool has_alpha = cmodel_has_alpha(color_model);
00317 if(is_yuv)
00318 shader = VFrame::make_shader(0, yuv_shader, 0);
00319 else
00320 shader = VFrame::make_shader(0, rgb_shader, 0);
00321
00322 if(shader > 0)
00323 {
00324 glUseProgram(shader);
00325 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
00326 glUniform1f(glGetUniformLocation(shader, "min"), config.min);
00327 glUniform1f(glGetUniformLocation(shader, "max"), config.max);
00328
00329 if (is_yuv)
00330 {
00331 float y_low, u_low, v_low;
00332 float y_mid, u_mid, v_mid;
00333 float y_high, u_high, v_high;
00334
00335 YUV::rgb_to_yuv_f((float)config.low_color.r / 0xff,
00336 (float)config.low_color.g / 0xff,
00337 (float)config.low_color.b / 0xff,
00338 y_low,
00339 u_low,
00340 v_low);
00341 u_low += 0.5;
00342 v_low += 0.5;
00343 YUV::rgb_to_yuv_f((float)config.mid_color.r / 0xff,
00344 (float)config.mid_color.g / 0xff,
00345 (float)config.mid_color.b / 0xff,
00346 y_mid,
00347 u_mid,
00348 v_mid);
00349 u_mid += 0.5;
00350 v_mid += 0.5;
00351 YUV::rgb_to_yuv_f((float)config.high_color.r / 0xff,
00352 (float)config.high_color.g / 0xff,
00353 (float)config.high_color.b / 0xff,
00354 y_high,
00355 u_high,
00356 v_high);
00357 u_high += 0.5;
00358 v_high += 0.5;
00359
00360 glUniform4f(glGetUniformLocation(shader, "low_color"),
00361 y_low, u_low, v_low,
00362 has_alpha ? (float)config.low_color.a / 0xff : 1.0);
00363 glUniform4f(glGetUniformLocation(shader, "mid_color"),
00364 y_mid, u_mid, v_mid,
00365 has_alpha ? (float)config.mid_color.a / 0xff : 1.0);
00366 glUniform4f(glGetUniformLocation(shader, "high_color"),
00367 y_high, u_high, v_high,
00368 has_alpha ? (float)config.high_color.a / 0xff : 1.0);
00369 } else {
00370 glUniform4f(glGetUniformLocation(shader, "low_color"),
00371 (float)config.low_color.r / 0xff,
00372 (float)config.low_color.g / 0xff,
00373 (float)config.low_color.b / 0xff,
00374 has_alpha ? (float)config.low_color.a / 0xff : 1.0);
00375 glUniform4f(glGetUniformLocation(shader, "mid_color"),
00376 (float)config.mid_color.r / 0xff,
00377 (float)config.mid_color.g / 0xff,
00378 (float)config.mid_color.b / 0xff,
00379 has_alpha ? (float)config.mid_color.a / 0xff : 1.0);
00380 glUniform4f(glGetUniformLocation(shader, "high_color"),
00381 (float)config.high_color.r / 0xff,
00382 (float)config.high_color.g / 0xff,
00383 (float)config.high_color.b / 0xff,
00384 has_alpha ? (float)config.high_color.a / 0xff : 1.0);
00385 }
00386 }
00387
00388 get_output()->init_screen();
00389 get_output()->bind_texture(0);
00390 get_output()->draw_texture();
00391 glUseProgram(0);
00392 get_output()->set_opengl_state(VFrame::SCREEN);
00393 #endif
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 ThresholdPackage::ThresholdPackage()
00419 : LoadPackage()
00420 {
00421 start = end = 0;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 ThresholdUnit::ThresholdUnit(ThresholdEngine *server)
00435 : LoadClient(server)
00436 {
00437 this->server = server;
00438 }
00439
00440
00441 static inline int get_component(unsigned char v)
00442 {
00443 return (v << 8) | v;
00444 }
00445
00446 static inline int get_component(float v)
00447 {
00448 return (int)(v * 0xffff);
00449 }
00450
00451 static inline int get_component(uint16_t v)
00452 {
00453 return v;
00454 }
00455
00456
00457 template<typename TYPE>
00458 static TYPE scale_to_range(int v)
00459 {
00460 return v;
00461 }
00462
00463 template<>
00464 static inline float scale_to_range(int v)
00465 {
00466 return (float) v / 0xff;
00467 }
00468
00469 template<>
00470 static inline uint16_t scale_to_range(int v)
00471 {
00472 return v << 8 | v;
00473 }
00474
00475 static inline void rgb_to_yuv(YUV & yuv,
00476 unsigned char r, unsigned char g, unsigned char b,
00477 unsigned char & y, unsigned char & u, unsigned char & v)
00478 {
00479 yuv.rgb_to_yuv_8(r, g, b, y, u, v);
00480 }
00481
00482 static inline void rgb_to_yuv(YUV & yuv,
00483 float r, float g, float b,
00484 float & y, float & u, float & v)
00485 {
00486 yuv.rgb_to_yuv_f(r, g, b, y, u, v);
00487 }
00488
00489 static inline void rgb_to_yuv(YUV & yuv,
00490 uint16_t r, uint16_t g, uint16_t b,
00491 uint16_t & y, uint16_t & u, uint16_t & v)
00492 {
00493 yuv.rgb_to_yuv_16(r, g, b, y, u, v);
00494 }
00495
00496 template<typename TYPE, int COMPONENTS, bool USE_YUV>
00497 void ThresholdUnit::render_data(LoadPackage *package)
00498 {
00499 const ThresholdPackage *pkg = (ThresholdPackage*)package;
00500 const ThresholdConfig *config = & server->plugin->config;
00501 VFrame *data = server->data;
00502 const int min = (int)(config->min * 0xffff);
00503 const int max = (int)(config->max * 0xffff);
00504 const int w = data->get_w();
00505 const int h = data->get_h();
00506
00507 const TYPE r_low = scale_to_range<TYPE>(config->low_color.r);
00508 const TYPE g_low = scale_to_range<TYPE>(config->low_color.g);
00509 const TYPE b_low = scale_to_range<TYPE>(config->low_color.b);
00510 const TYPE a_low = scale_to_range<TYPE>(config->low_color.a);
00511
00512 const TYPE r_mid = scale_to_range<TYPE>(config->mid_color.r);
00513 const TYPE g_mid = scale_to_range<TYPE>(config->mid_color.g);
00514 const TYPE b_mid = scale_to_range<TYPE>(config->mid_color.b);
00515 const TYPE a_mid = scale_to_range<TYPE>(config->mid_color.a);
00516
00517 const TYPE r_high = scale_to_range<TYPE>(config->high_color.r);
00518 const TYPE g_high = scale_to_range<TYPE>(config->high_color.g);
00519 const TYPE b_high = scale_to_range<TYPE>(config->high_color.b);
00520 const TYPE a_high = scale_to_range<TYPE>(config->high_color.a);
00521
00522 TYPE y_low, u_low, v_low;
00523 TYPE y_mid, u_mid, v_mid;
00524 TYPE y_high, u_high, v_high;
00525
00526 if (USE_YUV)
00527 {
00528 rgb_to_yuv(*server->yuv, r_low, g_low, b_low, y_low, u_low, v_low);
00529 rgb_to_yuv(*server->yuv, r_mid, g_mid, b_mid, y_mid, u_mid, v_mid);
00530 rgb_to_yuv(*server->yuv, r_high, g_high, b_high, y_high, u_high, v_high);
00531 }
00532
00533 for(int i = pkg->start; i < pkg->end; i++)
00534 {
00535 TYPE *in_row = (TYPE*)data->get_rows()[i];
00536 TYPE *out_row = in_row;
00537 for(int j = 0; j < w; j++)
00538 {
00539 if (USE_YUV)
00540 {
00541 const int y = get_component(in_row[0]);
00542 if (y < min)
00543 {
00544 *out_row++ = y_low;
00545 *out_row++ = u_low;
00546 *out_row++ = v_low;
00547 if(COMPONENTS == 4) *out_row++ = a_low;
00548 }
00549 else if (y < max)
00550 {
00551 *out_row++ = y_mid;
00552 *out_row++ = u_mid;
00553 *out_row++ = v_mid;
00554 if(COMPONENTS == 4) *out_row++ = a_mid;
00555 }
00556 else
00557 {
00558 *out_row++ = y_high;
00559 *out_row++ = u_high;
00560 *out_row++ = v_high;
00561 if(COMPONENTS == 4) *out_row++ = a_high;
00562 }
00563 }
00564 else
00565 {
00566 const int r = get_component(in_row[0]);
00567 const int g = get_component(in_row[1]);
00568 const int b = get_component(in_row[2]);
00569 const int y = (r * 76 + g * 150 + b * 29) >> 8;
00570 if (y < min)
00571 {
00572 *out_row++ = r_low;
00573 *out_row++ = g_low;
00574 *out_row++ = b_low;
00575 if(COMPONENTS == 4) *out_row++ = a_low;
00576 }
00577 else if (y < max)
00578 {
00579 *out_row++ = r_mid;
00580 *out_row++ = g_mid;
00581 *out_row++ = b_mid;
00582 if(COMPONENTS == 4) *out_row++ = a_mid;
00583 }
00584 else
00585 {
00586 *out_row++ = r_high;
00587 *out_row++ = g_high;
00588 *out_row++ = b_high;
00589 if(COMPONENTS == 4) *out_row++ = a_high;
00590 }
00591 }
00592 in_row += COMPONENTS;
00593 }
00594 }
00595 }
00596
00597 void ThresholdUnit::process_package(LoadPackage *package)
00598 {
00599 switch(server->data->get_color_model())
00600 {
00601 case BC_RGB888:
00602 render_data<unsigned char, 3, false>(package);
00603 break;
00604
00605 case BC_RGB_FLOAT:
00606 render_data<float, 3, false>(package);
00607 break;
00608
00609 case BC_RGBA8888:
00610 render_data<unsigned char, 4, false>(package);
00611 break;
00612
00613 case BC_RGBA_FLOAT:
00614 render_data<float, 4, false>(package);
00615 break;
00616
00617 case BC_YUV888:
00618 render_data<unsigned char, 3, true>(package);
00619 break;
00620
00621 case BC_YUVA8888:
00622 render_data<unsigned char, 4, true>(package);
00623 break;
00624
00625 case BC_YUV161616:
00626 render_data<uint16_t, 3, true>(package);
00627 break;
00628
00629 case BC_YUVA16161616:
00630 render_data<uint16_t, 4, true>(package);
00631 break;
00632 }
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 ThresholdEngine::ThresholdEngine(ThresholdMain *plugin)
00646 : LoadServer(plugin->get_project_smp() + 1,
00647 plugin->get_project_smp() + 1)
00648 {
00649 this->plugin = plugin;
00650 yuv = new YUV;
00651 }
00652
00653 ThresholdEngine::~ThresholdEngine()
00654 {
00655 delete yuv;
00656 }
00657
00658 void ThresholdEngine::process_packages(VFrame *data)
00659 {
00660 this->data = data;
00661 LoadServer::process_packages();
00662 }
00663
00664 void ThresholdEngine::init_packages()
00665 {
00666 for(int i = 0; i < get_total_packages(); i++)
00667 {
00668 ThresholdPackage *package = (ThresholdPackage*)get_package(i);
00669 package->start = data->get_h() * i / get_total_packages();
00670 package->end = data->get_h() * (i + 1) / get_total_packages();
00671 }
00672 }
00673
00674 LoadClient* ThresholdEngine::new_client()
00675 {
00676 return (LoadClient*)new ThresholdUnit(this);
00677 }
00678
00679 LoadPackage* ThresholdEngine::new_package()
00680 {
00681 return (LoadPackage*)new HistogramPackage;
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691 RGBA::RGBA()
00692 {
00693 r = g = b = a = 0;
00694 }
00695
00696 RGBA::RGBA(int r, int g, int b, int a)
00697 {
00698 this->r = r;
00699 this->g = g;
00700 this->b = b;
00701 this->a = a;
00702 }
00703
00704 void RGBA::set(int r, int g, int b, int a)
00705 {
00706 this->r = r;
00707 this->g = g;
00708 this->b = b;
00709 this->a = a;
00710 }
00711
00712 void RGBA::set(int rgb, int alpha)
00713 {
00714 r = (rgb & 0xff0000) >> 16;
00715 g = (rgb & 0xff00) >> 8;
00716 b = (rgb & 0xff);
00717 a = alpha;
00718 }
00719
00720 int RGBA::getRGB() const
00721 {
00722 return r << 16 | g << 8 | b;
00723 }
00724
00725 static void init_RGBA_keys(const char * prefix,
00726 string & r_s,
00727 string & g_s,
00728 string & b_s,
00729 string & a_s)
00730 {
00731 r_s = prefix;
00732 g_s = prefix;
00733 b_s = prefix;
00734 a_s = prefix;
00735
00736 r_s += "_R";
00737 g_s += "_G";
00738 b_s += "_B";
00739 a_s += "_A";
00740 }
00741
00742 RGBA RGBA::load_default(BC_Hash * defaults, const char * prefix) const
00743 {
00744 string r_s, g_s, b_s, a_s;
00745 init_RGBA_keys(prefix, r_s, g_s, b_s, a_s);
00746
00747 return RGBA(defaults->get(const_cast<char *>(r_s.c_str()), r),
00748 defaults->get(const_cast<char *>(g_s.c_str()), g),
00749 defaults->get(const_cast<char *>(b_s.c_str()), b),
00750 defaults->get(const_cast<char *>(a_s.c_str()), a));
00751 }
00752
00753 void RGBA::save_defaults(BC_Hash * defaults, const char * prefix) const
00754 {
00755 string r_s, g_s, b_s, a_s;
00756 init_RGBA_keys(prefix, r_s, g_s, b_s, a_s);
00757
00758 defaults->update(const_cast<char *>(r_s.c_str()), r);
00759 defaults->update(const_cast<char *>(g_s.c_str()), g);
00760 defaults->update(const_cast<char *>(b_s.c_str()), b);
00761 defaults->update(const_cast<char *>(a_s.c_str()), a);
00762 }
00763
00764 void RGBA::set_property(XMLTag & tag, const char * prefix) const
00765 {
00766 string r_s, g_s, b_s, a_s;
00767 init_RGBA_keys(prefix, r_s, g_s, b_s, a_s);
00768
00769 tag.set_property(const_cast<char *>(r_s.c_str()), r);
00770 tag.set_property(const_cast<char *>(g_s.c_str()), g);
00771 tag.set_property(const_cast<char *>(b_s.c_str()), b);
00772 tag.set_property(const_cast<char *>(a_s.c_str()), a);
00773 }
00774
00775 RGBA RGBA::get_property(XMLTag & tag, const char * prefix) const
00776 {
00777 string r_s, g_s, b_s, a_s;
00778 init_RGBA_keys(prefix, r_s, g_s, b_s, a_s);
00779
00780 return RGBA(tag.get_property(const_cast<char *>(r_s.c_str()), r),
00781 tag.get_property(const_cast<char *>(g_s.c_str()), g),
00782 tag.get_property(const_cast<char *>(b_s.c_str()), b),
00783 tag.get_property(const_cast<char *>(a_s.c_str()), a));
00784 }
00785
00786 bool operator==(const RGBA & a, const RGBA & b)
00787 {
00788 return a.r == b.r &&
00789 a.g == b.g &&
00790 a.b == b.b &&
00791 a.a == b.a;
00792 }
00793
00794 template<>
00795 RGBA interpolate(const RGBA & prev_color, const double & prev_scale, const RGBA &next_color, const double & next_scale)
00796 {
00797 return RGBA(interpolate(prev_color.r, prev_scale, next_color.r, next_scale),
00798 interpolate(prev_color.g, prev_scale, next_color.g, next_scale),
00799 interpolate(prev_color.b, prev_scale, next_color.b, next_scale),
00800 interpolate(prev_color.a, prev_scale, next_color.a, next_scale));
00801 }