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 "colormodels.h"
26 #include "aggregated.h"
28 #include "interpolate.h"
34 REGISTER_PLUGIN(InterpolatePixelsMain)
41 InterpolatePixelsOffset::InterpolatePixelsOffset(InterpolatePixelsWindow *window,
55 this->window = window;
56 this->output = output;
59 InterpolatePixelsOffset::~InterpolatePixelsOffset()
63 int InterpolatePixelsOffset::handle_event()
65 *output = get_value();
66 window->client->send_configure_change();
75 InterpolatePixelsWindow::InterpolatePixelsWindow(InterpolatePixelsMain *client)
76 : PluginClientWindow(client,
83 this->client = client;
86 InterpolatePixelsWindow::~InterpolatePixelsWindow()
90 void InterpolatePixelsWindow::create_objects()
95 add_tool(title = new BC_Title(x, y, _("X Offset:")));
96 add_tool(x_offset = new InterpolatePixelsOffset(this,
97 x + title->get_w() + 5,
100 y += MAX(x_offset->get_h(), title->get_h()) + 5;
101 add_tool(title = new BC_Title(x, y, _("Y Offset:")));
102 add_tool(y_offset = new InterpolatePixelsOffset(this,
103 x + title->get_w() + 5,
106 y += MAX(y_offset->get_h(), title->get_h()) + 5;
125 InterpolatePixelsConfig::InterpolatePixelsConfig()
131 int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that)
133 return x == that.x && y == that.y;
136 void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that)
142 void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev,
143 InterpolatePixelsConfig &next,
144 int64_t prev_position,
145 int64_t next_position,
146 int64_t current_position)
157 InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server)
158 : PluginVClient(server)
164 InterpolatePixelsMain::~InterpolatePixelsMain()
170 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Pixels"); }
171 int InterpolatePixelsMain::is_realtime() { return 1; }
174 NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow)
177 void InterpolatePixelsMain::update_gui()
181 int changed = load_configuration();
184 thread->window->lock_window("InterpolatePixelsMain::update_gui");
185 ((InterpolatePixelsWindow*)thread->window)->x_offset->update(config.x);
186 ((InterpolatePixelsWindow*)thread->window)->y_offset->update(config.y);
187 thread->window->unlock_window();
193 LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig)
196 void InterpolatePixelsMain::save_data(KeyFrame *keyframe)
200 // cause data to be stored directly in text
201 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
202 output.tag.set_title("INTERPOLATEPIXELS");
203 output.tag.set_property("X", config.x);
204 output.tag.set_property("Y", config.y);
206 output.terminate_string();
209 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
213 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
219 result = input.read_tag();
223 if(input.tag.title_is("INTERPOLATEPIXELS"))
225 config.x = input.tag.get_property("X", config.x);
226 config.y = input.tag.get_property("Y", config.y);
234 int InterpolatePixelsMain::process_buffer(VFrame *frame,
235 int64_t start_position,
238 load_configuration();
240 // Set aggregation parameters
241 frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
242 frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
249 //frame->dump_params();
253 // Aggregate with gamma
254 if(next_effect_is("Gamma") ||
255 next_effect_is("Histogram") ||
256 next_effect_is("Color Balance"))
264 if(get_output()->get_color_model() != BC_RGB_FLOAT &&
265 get_output()->get_color_model() != BC_RGBA_FLOAT)
267 printf("InterpolatePixelsMain::process_buffer: only supports float colormodels\n");
271 new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
272 get_temp()->copy_from(frame);
274 engine = new InterpolatePixelsEngine(this);
275 engine->process_packages();
283 // And is offset to recreate the 4 possibilities.
284 // The color values are interpolated in the most basic way.
285 // No adaptive algorithm is used.
287 int InterpolatePixelsMain::handle_opengl()
289 //printf("InterpolatePixelsMain::handle_opengl\n");
293 get_output()->to_texture();
294 get_output()->enable_opengl();
296 const char *shader_stack[] = { 0, 0, 0 };
297 int current_shader = 0;
298 INTERPOLATE_COMPILE(shader_stack, current_shader)
299 unsigned int frag = VFrame::make_shader(0,
305 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
306 INTERPOLATE_UNIFORMS(frag)
310 get_output()->init_screen();
311 get_output()->bind_texture(0);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
316 get_output()->draw_texture();
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
320 get_output()->set_opengl_state(VFrame::SCREEN);
338 InterpolatePixelsPackage::InterpolatePixelsPackage()
349 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
352 this->plugin = plugin;
353 this->server = server;
356 void InterpolatePixelsUnit::process_package(LoadPackage *package)
358 InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package;
359 int h = plugin->get_temp()->get_h();
360 int w = plugin->get_temp()->get_w();
361 int pattern_offset_x = plugin->config.x;
362 int pattern_offset_y = plugin->config.y;
365 int components = cmodel_components(plugin->get_output()->get_color_model());
366 float color_matrix[9];
367 memcpy(color_matrix, server->color_matrix, sizeof(color_matrix));
372 // Only supports float because it's useless in any other colormodel.
373 for(int i = y1; i < y2; i++)
375 int pattern_coord_y = (i - pattern_offset_y) % 2;
376 float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1];
377 float *current_row = (float*)plugin->get_temp()->get_rows()[i];
378 float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1];
379 float *out_row = (float*)plugin->get_output()->get_rows()[i];
381 prev_row += components;
382 current_row += components;
383 next_row += components;
384 out_row += components;
394 if(pattern_coord_y == 0)
396 for(int j = 1; j < w - 1; j++)
398 int pattern_coord_x = (j - pattern_offset_x) % 2;
400 if(pattern_coord_x == 0)
402 r = (prev_row[RED] + next_row[RED]) / 2;
403 g = current_row[GREEN];
404 b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2;
409 r = (prev_row[-components + RED] +
410 prev_row[components + RED] +
411 next_row[-components + RED] +
412 next_row[components + RED]) / 4;
413 g = (current_row[-components + GREEN] +
415 current_row[components + GREEN] +
416 next_row[GREEN]) / 4;
417 b = current_row[BLUE];
420 out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
421 out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
422 out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
423 prev_row += components;
424 current_row += components;
425 next_row += components;
426 out_row += components;
431 for(int j = 1; j < w - 1; j++)
433 int pattern_coord_x = (j - pattern_offset_x) % 2;
435 if(pattern_coord_x == 0)
437 r = current_row[RED];
438 g = (current_row[-components + GREEN] +
440 current_row[components + GREEN] +
441 next_row[GREEN]) / 4;
442 b = (prev_row[-components + BLUE] +
443 prev_row[components + BLUE] +
444 next_row[-components + BLUE] +
445 next_row[components + BLUE]) / 4;
448 // Bottom right pixel
450 r = (current_row[-components + RED] + current_row[components + RED]) / 2;
451 g = current_row[GREEN];
452 b = (prev_row[BLUE] + next_row[BLUE]) / 2;
455 out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
456 out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
457 out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
458 prev_row += components;
459 current_row += components;
460 next_row += components;
461 out_row += components;
470 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
471 : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
473 this->plugin = plugin;
476 void InterpolatePixelsEngine::init_packages()
478 char string[BCTEXTLEN];
480 plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
482 "%f %f %f %f %f %f %f %f %f",
492 for(int i = 0; i < get_total_packages(); i++)
494 InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i);
495 package->y1 = plugin->get_temp()->get_h() * i / get_total_packages();
496 package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages();
501 LoadClient* InterpolatePixelsEngine::new_client()
503 return new InterpolatePixelsUnit(this, plugin);
507 LoadPackage* InterpolatePixelsEngine::new_package()
509 return new InterpolatePixelsPackage;