7 #include "plugincolors.h"
8 #include "../interpolate/aggregated.h"
9 #include "playback3d.h"
10 #include "workarounds.h"
16 #include "aggregated.h"
18 #define SQR(a) ((a) * (a))
20 REGISTER_PLUGIN(GammaMain)
24 GammaConfig::GammaConfig()
32 int GammaConfig::equivalent(GammaConfig &that)
34 return (EQUIV(max, that.max) &&
35 EQUIV(gamma, that.gamma) &&
36 automatic == that.automatic) &&
40 void GammaConfig::copy_from(GammaConfig &that)
44 automatic = that.automatic;
48 void GammaConfig::interpolate(GammaConfig &prev,
52 int64_t current_frame)
54 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
55 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
57 this->max = prev.max * prev_scale + next.max * next_scale;
58 this->gamma = prev.gamma * prev_scale + next.gamma * next_scale;
59 this->automatic = prev.automatic;
60 this->plot = prev.plot;
70 GammaPackage::GammaPackage()
85 GammaUnit::GammaUnit(GammaMain *plugin)
87 this->plugin = plugin;
91 void GammaUnit::process_package(LoadPackage *package)
93 GammaPackage *pkg = (GammaPackage*)package;
94 GammaEngine *engine = (GammaEngine*)get_server();
95 VFrame *data = engine->data;
96 int w = data->get_w();
97 float r, g, b, y, u, v;
99 // The same algorithm used by dcraw
100 if(engine->operation == GammaEngine::HISTOGRAM)
102 #define HISTOGRAM_HEAD(type) \
103 for(int i = pkg->start; i < pkg->end; i++) \
105 type *row = (type*)data->get_rows()[i]; \
106 for(int j = 0; j < w; j++) \
109 #define HISTOGRAM_TAIL(components) \
111 slot = (int)(r * HISTOGRAM_SIZE); \
112 accum[CLIP(slot, 0, HISTOGRAM_SIZE - 1)]++; \
113 slot = (int)(g * HISTOGRAM_SIZE); \
114 accum[CLIP(slot, 0, HISTOGRAM_SIZE - 1)]++; \
115 slot = (int)(b * HISTOGRAM_SIZE); \
116 accum[CLIP(slot, 0, HISTOGRAM_SIZE - 1)]++; \
122 switch(data->get_color_model())
125 HISTOGRAM_HEAD(unsigned char)
126 r = (float)row[0] / 0xff;
127 g = (float)row[1] / 0xff;
128 b = (float)row[2] / 0xff;
132 HISTOGRAM_HEAD(unsigned char)
133 r = (float)row[0] / 0xff;
134 g = (float)row[1] / 0xff;
135 b = (float)row[2] / 0xff;
139 HISTOGRAM_HEAD(float)
146 HISTOGRAM_HEAD(float)
153 HISTOGRAM_HEAD(unsigned char)
158 u = (float)((u - 0x80) / 0xff);
159 v = (float)((v - 0x80) / 0xff);
160 YUV::yuv_to_rgb_f(r, g, b, y, u, v);
164 HISTOGRAM_HEAD(unsigned char)
165 y = (float)row[0] / 0xff;
166 u = (float)row[1] / 0xff;
167 v = (float)row[2] / 0xff;
168 YUV::yuv_to_rgb_f(r, g, b, y, u, v);
175 float max = plugin->config.max;
176 float scale = 1.0 / max;
177 float gamma = plugin->config.gamma - 1.0;
179 #define GAMMA_HEAD(type) \
180 for(int i = pkg->start; i < pkg->end; i++) \
182 type *row = (type*)data->get_rows()[i]; \
183 for(int j = 0; j < w; j++) \
186 // powf errors don't show up until later in the pipeline, which makes
187 // this very hard to isolate.
188 #define MY_POW(x, y) ((x > 0.0) ? powf(x * 2 / max, y) : 0.0)
191 r = r * scale * MY_POW(r, gamma); \
192 g = g * scale * MY_POW(g, gamma); \
193 b = b * scale * MY_POW(b, gamma); \
195 #define GAMMA_TAIL(components) \
201 switch(data->get_color_model())
204 GAMMA_HEAD(unsigned char)
205 r = (float)row[0] / 0xff;
206 g = (float)row[1] / 0xff;
207 b = (float)row[2] / 0xff;
209 row[0] = (int)CLIP(r * 0xff, 0, 0xff);
210 row[1] = (int)CLIP(g * 0xff, 0, 0xff);
211 row[2] = (int)CLIP(b * 0xff, 0, 0xff);
215 GAMMA_HEAD(unsigned char)
216 r = (float)row[0] / 0xff;
217 g = (float)row[1] / 0xff;
218 b = (float)row[2] / 0xff;
220 row[0] = (int)CLIP(r * 0xff, 0, 0xff);
221 row[1] = (int)CLIP(g * 0xff, 0, 0xff);
222 row[2] = (int)CLIP(b * 0xff, 0, 0xff);
248 GAMMA_HEAD(unsigned char)
253 u = (float)((u - 0x80) / 0xff);
254 v = (float)((v - 0x80) / 0xff);
255 YUV::yuv_to_rgb_f(r, g, b, y, u, v);
257 YUV::rgb_to_yuv_f(r, g, b, y, u, v);
261 row[0] = (int)CLIP(y, 0, 0xff);
262 row[1] = (int)CLIP(u, 0, 0xff);
263 row[2] = (int)CLIP(v, 0, 0xff);
267 GAMMA_HEAD(unsigned char)
272 u = (float)((u - 0x80) / 0xff);
273 v = (float)((v - 0x80) / 0xff);
274 YUV::yuv_to_rgb_f(r, g, b, y, u, v);
276 YUV::rgb_to_yuv_f(r, g, b, y, u, v);
280 row[0] = (int)CLIP(y, 0, 0xff);
281 row[1] = (int)CLIP(u, 0, 0xff);
282 row[2] = (int)CLIP(v, 0, 0xff);
299 GammaEngine::GammaEngine(GammaMain *plugin)
300 : LoadServer(plugin->get_project_smp() + 1,
301 plugin->get_project_smp() + 1)
303 this->plugin = plugin;
306 void GammaEngine::init_packages()
308 for(int i = 0; i < get_total_packages(); i++)
310 GammaPackage *package = (GammaPackage*)get_package(i);
311 package->start = data->get_h() * i / get_total_packages();
312 package->end = data->get_h() * (i + 1) / get_total_packages();
315 // Initialize clients here in case some don't get run.
316 for(int i = 0; i < get_total_clients(); i++)
318 GammaUnit *unit = (GammaUnit*)get_client(i);
319 bzero(unit->accum, sizeof(int) * HISTOGRAM_SIZE);
321 bzero(accum, sizeof(int) * HISTOGRAM_SIZE);
324 LoadClient* GammaEngine::new_client()
326 return new GammaUnit(plugin);
329 LoadPackage* GammaEngine::new_package()
331 return new GammaPackage;
334 void GammaEngine::process_packages(int operation, VFrame *data)
337 this->operation = operation;
338 LoadServer::process_packages();
339 for(int i = 0; i < get_total_clients(); i++)
341 GammaUnit *unit = (GammaUnit*)get_client(i);
342 for(int j = 0; j < HISTOGRAM_SIZE; j++)
344 accum[j] += unit->accum[j];
364 GammaMain::GammaMain(PluginServer *server)
365 : PluginVClient(server)
368 PLUGIN_CONSTRUCTOR_MACRO
371 GammaMain::~GammaMain()
373 PLUGIN_DESTRUCTOR_MACRO
378 char* GammaMain::plugin_title() { return N_("Gamma"); }
379 int GammaMain::is_realtime() { return 1; }
385 NEW_PICON_MACRO(GammaMain)
386 LOAD_CONFIGURATION_MACRO(GammaMain, GammaConfig)
387 SHOW_GUI_MACRO(GammaMain, GammaThread)
388 RAISE_WINDOW_MACRO(GammaMain)
389 SET_STRING_MACRO(GammaMain)
395 int GammaMain::process_buffer(VFrame *frame,
396 int64_t start_position,
400 load_configuration();
402 frame->get_params()->update("GAMMA_GAMMA", config.gamma);
403 frame->get_params()->update("GAMMA_MAX", config.max);
405 int use_opengl = get_use_opengl() &&
407 (!config.plot || !gui_open());
418 if(next_effect_is("Histogram"))
420 if(next_effect_is("Color Balance"))
429 calculate_max(frame);
430 // Always plot to set the slider
431 send_render_gui(this);
436 send_render_gui(this);
439 if(!engine) engine = new GammaEngine(this);
440 engine->process_packages(GammaEngine::APPLY, frame);
444 void GammaMain::calculate_max(VFrame *frame)
446 if(!engine) engine = new GammaEngine(this);
447 engine->process_packages(GammaEngine::HISTOGRAM, frame);
448 int total_pixels = frame->get_w() * frame->get_h() * 3;
449 int max_fraction = (int)((int64_t)total_pixels * 99 / 100);
452 for(int i = 0; i < HISTOGRAM_SIZE; i++)
454 current += engine->accum[i];
455 if(current > max_fraction)
457 config.max = (float)i / HISTOGRAM_SIZE;
464 void GammaMain::update_gui()
468 if(load_configuration())
470 thread->window->lock_window("GammaMain::update_gui");
471 thread->window->update();
472 thread->window->unlock_window();
477 void GammaMain::render_gui(void *data)
479 GammaMain *ptr = (GammaMain*)data;
480 config.max = ptr->config.max;
482 if(!engine) engine = new GammaEngine(this);
483 if(ptr->engine && ptr->config.automatic)
485 memcpy(engine->accum,
487 sizeof(int) * HISTOGRAM_SIZE);
488 thread->window->lock_window("GammaMain::render_gui");
489 thread->window->update();
490 thread->window->unlock_window();
494 engine->process_packages(GammaEngine::HISTOGRAM,
496 thread->window->lock_window("GammaMain::render_gui");
497 thread->window->update_histogram();
498 thread->window->unlock_window();
504 int GammaMain::load_defaults()
506 char directory[1024], string[1024];
507 // set the default directory
508 sprintf(directory, "%sgamma.rc", BCASTDIR);
511 defaults = new BC_Hash(directory);
514 config.max = defaults->get("MAX", config.max);
515 config.gamma = defaults->get("GAMMA", config.gamma);
516 config.automatic = defaults->get("AUTOMATIC", config.automatic);
517 config.plot = defaults->get("PLOT", config.plot);
521 int GammaMain::save_defaults()
523 defaults->update("MAX", config.max);
524 defaults->update("GAMMA", config.gamma);
525 defaults->update("AUTOMATIC", config.automatic);
526 defaults->update("PLOT", config.plot);
531 void GammaMain::save_data(KeyFrame *keyframe)
535 // cause data to be stored directly in text
536 output.set_shared_string(keyframe->data, MESSAGESIZE);
537 output.tag.set_title("GAMMA");
538 output.tag.set_property("MAX", config.max);
539 output.tag.set_property("GAMMA", config.gamma);
540 output.tag.set_property("AUTOMATIC", config.automatic);
541 output.tag.set_property("PLOT", config.plot);
543 output.terminate_string();
546 void GammaMain::read_data(KeyFrame *keyframe)
550 input.set_shared_string(keyframe->data, strlen(keyframe->data));
556 result = input.read_tag();
560 if(input.tag.title_is("GAMMA"))
562 config.max = input.tag.get_property("MAX", config.max);
563 config.gamma = input.tag.get_property("GAMMA", config.gamma);
564 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
565 config.plot = input.tag.get_property("PLOT", config.plot);
566 //printf("GammaMain::read_data %f\n", config.max);
572 int GammaMain::handle_opengl()
575 //printf("GammaMain::handle_opengl 1\n");
577 get_output()->to_texture();
578 get_output()->enable_opengl();
581 char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
582 int current_shader = 0;
585 // Aggregate with interpolate
587 if(prev_effect_is("Interpolate Pixels"))
590 INTERPOLATE_COMPILE(shader_stack, current_shader)
593 GAMMA_COMPILE(shader_stack, current_shader, aggregate);
595 unsigned int shader = VFrame::make_shader(0,
609 glUseProgram(shader);
610 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
614 INTERPOLATE_UNIFORMS(shader)
616 GAMMA_UNIFORMS(shader)
619 get_output()->init_screen();
620 get_output()->bind_texture(0);
621 get_output()->draw_texture();
623 get_output()->set_opengl_state(VFrame::SCREEN);