4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
24 #include "bccmodels.h"
26 #include "aggregated.h"
28 #include "interpolate.h"
34 REGISTER_PLUGIN(InterpolatePixelsMain)
41 InterpolatePixelsOffset::InterpolatePixelsOffset(InterpolatePixelsWindow *window,
45 : BC_ISlider(x, y, 0, xS(50), yS(50), 0, 1, *output, 0)
47 this->window = window;
48 this->output = output;
51 InterpolatePixelsOffset::~InterpolatePixelsOffset()
55 int InterpolatePixelsOffset::handle_event()
57 *output = get_value();
58 window->client->send_configure_change();
67 InterpolatePixelsWindow::InterpolatePixelsWindow(InterpolatePixelsMain *client)
68 : PluginClientWindow(client,
69 xS(200), yS(70), xS(200), yS(70), 0)
71 this->client = client;
74 InterpolatePixelsWindow::~InterpolatePixelsWindow()
78 void InterpolatePixelsWindow::create_objects()
80 int xs5 = xS(5), xs10 = xS(10);
81 int ys5 = yS(5), ys10 = yS(10);
82 int x = xs10, y = ys10;
85 add_tool(title = new BC_Title(x, y, _("X Offset:")));
86 add_tool(x_offset = new InterpolatePixelsOffset(this,
87 x + title->get_w() + xs5,
90 y += MAX(x_offset->get_h(), title->get_h()) + ys5;
91 add_tool(title = new BC_Title(x, y, _("Y Offset:")));
92 add_tool(y_offset = new InterpolatePixelsOffset(this,
93 x + title->get_w() + xs5,
96 y += MAX(y_offset->get_h(), title->get_h()) + ys5;
115 InterpolatePixelsConfig::InterpolatePixelsConfig()
121 int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that)
123 return x == that.x && y == that.y;
126 void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that)
132 void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev,
133 InterpolatePixelsConfig &next,
134 int64_t prev_position,
135 int64_t next_position,
136 int64_t current_position)
147 InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server)
148 : PluginVClient(server)
150 out_temp = out_frame = 0;
154 InterpolatePixelsMain::~InterpolatePixelsMain()
160 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Bayer"); }
161 int InterpolatePixelsMain::is_realtime() { return 1; }
164 NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow)
167 void InterpolatePixelsMain::update_gui()
171 int changed = load_configuration();
174 thread->window->lock_window("InterpolatePixelsMain::update_gui");
175 ((InterpolatePixelsWindow*)thread->window)->x_offset->update(config.x);
176 ((InterpolatePixelsWindow*)thread->window)->y_offset->update(config.y);
177 thread->window->unlock_window();
183 LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig)
186 void InterpolatePixelsMain::save_data(KeyFrame *keyframe)
190 // cause data to be stored directly in text
191 output.set_shared_output(keyframe->xbuf);
192 output.tag.set_title("INTERPOLATEPIXELS");
193 output.tag.set_property("X", config.x);
194 output.tag.set_property("Y", config.y);
196 output.tag.set_title("/INTERPOLATEPIXELS");
198 output.append_newline();
199 output.terminate_string();
202 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
206 input.set_shared_input(keyframe->xbuf);
212 result = input.read_tag();
216 if(input.tag.title_is("INTERPOLATEPIXELS"))
218 config.x = input.tag.get_property("X", config.x);
219 config.y = input.tag.get_property("Y", config.y);
225 int InterpolatePixelsMain::process_buffer(VFrame *frame,
226 int64_t start_position,
229 load_configuration();
231 // Set aggregation parameters
232 frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
233 frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
240 //frame->dump_params();
244 // Aggregate with gamma
245 if(next_effect_is(_("Gamma")) ||
246 next_effect_is(_("Histogram")) ||
247 next_effect_is(_("Color Balance")))
254 int color_model = frame->get_color_model();
255 int active_model = BC_CModels::has_alpha(color_model) ?
256 BC_RGBA_FLOAT : BC_RGB_FLOAT;
257 new_temp(frame->get_w(), frame->get_h(), active_model);
258 get_temp()->transfer_from(frame);
260 out_frame = get_output();
261 color_model = out_frame->get_color_model();
262 active_model = BC_CModels::has_alpha(color_model) ?
263 BC_RGBA_FLOAT : BC_RGB_FLOAT;
264 if( active_model != color_model ) {
265 int w = out_frame->get_w(), h = out_frame->get_h();
266 if( out_temp && ( out_temp->get_color_model() != active_model ||
267 out_temp->get_w() != w || out_temp->get_w() != h ) ) {
268 delete out_temp; out_temp = 0;
271 out_temp = new VFrame(w, h, active_model, 0);
272 out_frame = out_temp;
276 engine = new InterpolatePixelsEngine(this);
277 engine->process_packages();
279 if( out_frame != get_output() ) {
280 if( BC_CModels::has_alpha(out_frame->get_color_model()) ) {
281 unsigned char **out_rows = out_frame->get_rows();
282 int w = out_frame->get_w(), h = out_frame->get_h();
283 if( BC_CModels::has_alpha(get_temp()->get_color_model()) ) {
284 unsigned char **in_rows = get_temp()->get_rows();
285 for( int y=0; y<h; ++y ) {
286 float *inp = (float *)in_rows[y];
287 float *outp = (float *)out_rows[y];
288 for( int x=0; x<w; ++x,inp+=4,outp+=4 ) outp[3] = inp[3];
292 for( int y=0; y<h; ++y ) {
293 float *outp = (float *)out_rows[y];
294 for( int x=0; x<w; ++x,outp+=4 ) outp[3] = 1;
298 get_output()->transfer_from(out_frame);
307 // And is offset to recreate the 4 possibilities.
308 // The color values are interpolated in the most basic way.
309 // No adaptive algorithm is used.
311 int InterpolatePixelsMain::handle_opengl()
313 //printf("InterpolatePixelsMain::handle_opengl\n");
317 get_output()->to_texture();
318 get_output()->enable_opengl();
320 const char *shader_stack[16];
321 memset(shader_stack,0, sizeof(shader_stack));
322 int current_shader = 0;
324 INTERPOLATE_COMPILE(shader_stack, current_shader);
326 shader_stack[current_shader] = 0;
327 unsigned int shader = VFrame::make_shader(shader_stack);
329 glUseProgram(shader);
330 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
331 INTERPOLATE_UNIFORMS(shader);
334 get_output()->init_screen();
335 get_output()->bind_texture(0);
336 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
337 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340 get_output()->draw_texture();
341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
344 get_output()->set_opengl_state(VFrame::SCREEN);
362 InterpolatePixelsPackage::InterpolatePixelsPackage()
373 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
376 this->plugin = plugin;
377 this->server = server;
380 void InterpolatePixelsUnit::process_package(LoadPackage *package)
382 InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package;
383 int h = plugin->get_temp()->get_h();
384 int w = plugin->get_temp()->get_w();
385 int pattern_offset_x = plugin->config.x;
386 int pattern_offset_y = plugin->config.y;
389 int components = BC_CModels::components(plugin->out_frame->get_color_model());
390 float color_matrix[9];
391 memcpy(color_matrix, server->color_matrix, sizeof(color_matrix));
393 // printf("InterpolatePixelsUnit::process_package %d color_matrix=", __LINE__);
394 // for(int i = 0; i < 9; i++)
396 // printf("%f ", color_matrix[i]);
403 // Only supports float because it's useless in any other colormodel.
404 for(int i = y1; i < y2; i++)
406 int pattern_coord_y = (i - pattern_offset_y) % 2;
407 float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1];
408 float *current_row = (float*)plugin->get_temp()->get_rows()[i];
409 float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1];
410 float *out_row = (float*)plugin->out_frame->get_rows()[i];
412 prev_row += components;
413 current_row += components;
414 next_row += components;
415 out_row += components;
425 if(pattern_coord_y == 0)
427 for(int j = 1; j < w - 1; j++)
429 int pattern_coord_x = (j - pattern_offset_x) % 2;
431 if(pattern_coord_x == 0)
433 r = (prev_row[RED] + next_row[RED]) / 2;
434 g = current_row[GREEN];
435 b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2;
440 r = (prev_row[-components + RED] +
441 prev_row[components + RED] +
442 next_row[-components + RED] +
443 next_row[components + RED]) / 4;
444 g = (current_row[-components + GREEN] +
446 current_row[components + GREEN] +
447 next_row[GREEN]) / 4;
448 b = current_row[BLUE];
451 // out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
452 // out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
453 // out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
459 prev_row += components;
460 current_row += components;
461 next_row += components;
462 out_row += components;
467 for(int j = 1; j < w - 1; j++)
469 int pattern_coord_x = (j - pattern_offset_x) % 2;
471 if(pattern_coord_x == 0)
473 r = current_row[RED];
474 g = (current_row[-components + GREEN] +
476 current_row[components + GREEN] +
477 next_row[GREEN]) / 4;
478 b = (prev_row[-components + BLUE] +
479 prev_row[components + BLUE] +
480 next_row[-components + BLUE] +
481 next_row[components + BLUE]) / 4;
484 // Bottom right pixel
486 r = (current_row[-components + RED] + current_row[components + RED]) / 2;
487 g = current_row[GREEN];
488 b = (prev_row[BLUE] + next_row[BLUE]) / 2;
491 // out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
492 // out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
493 // out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
499 prev_row += components;
500 current_row += components;
501 next_row += components;
502 out_row += components;
511 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
512 : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
514 this->plugin = plugin;
517 void InterpolatePixelsEngine::init_packages()
519 for( int i=0; i<9; ++i ) color_matrix[i] = 0;
520 for( int i=0; i<3; ++i ) color_matrix[i*3 + i] = 1;
521 char string[BCTEXTLEN];
523 plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
525 // printf("InterpolatePixelsEngine::init_packages %d\n", __LINE__);
526 // plugin->get_output()->dump_params();
529 "%f %f %f %f %f %f %f %f %f",
539 for(int i = 0; i < get_total_packages(); i++)
541 InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i);
542 package->y1 = plugin->get_temp()->get_h() * i / get_total_packages();
543 package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages();
548 LoadClient* InterpolatePixelsEngine::new_client()
550 return new InterpolatePixelsUnit(this, plugin);
554 LoadPackage* InterpolatePixelsEngine::new_package()
556 return new InterpolatePixelsPackage;