/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bcdisplayinfo.h" #include "clip.h" #include "bccmodels.h" #include "filexml.h" #include "aggregated.h" #include "language.h" #include "interpolate.h" #include #include REGISTER_PLUGIN(InterpolatePixelsMain) InterpolatePixelsOffset::InterpolatePixelsOffset(InterpolatePixelsWindow *window, int x, int y, int *output) : BC_ISlider(x, y, 0, 50, 50, 0, 1, *output, 0) { this->window = window; this->output = output; } InterpolatePixelsOffset::~InterpolatePixelsOffset() { } int InterpolatePixelsOffset::handle_event() { *output = get_value(); window->client->send_configure_change(); return 1; } InterpolatePixelsWindow::InterpolatePixelsWindow(InterpolatePixelsMain *client) : PluginClientWindow(client, 200, 100, 200, 100, 0) { this->client = client; } InterpolatePixelsWindow::~InterpolatePixelsWindow() { } void InterpolatePixelsWindow::create_objects() { int x = 10, y = 10; BC_Title *title; add_tool(title = new BC_Title(x, y, _("X Offset:"))); add_tool(x_offset = new InterpolatePixelsOffset(this, x + title->get_w() + 5, y, &client->config.x)); y += MAX(x_offset->get_h(), title->get_h()) + 5; add_tool(title = new BC_Title(x, y, _("Y Offset:"))); add_tool(y_offset = new InterpolatePixelsOffset(this, x + title->get_w() + 5, y, &client->config.y)); y += MAX(y_offset->get_h(), title->get_h()) + 5; show_window(); } InterpolatePixelsConfig::InterpolatePixelsConfig() { x = 0; y = 0; } int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that) { return x == that.x && y == that.y; } void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that) { x = that.x; y = that.y; } void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev, InterpolatePixelsConfig &next, int64_t prev_position, int64_t next_position, int64_t current_position) { this->x = prev.x; this->y = prev.y; } InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server) : PluginVClient(server) { out_temp = out_frame = 0; engine = 0; } InterpolatePixelsMain::~InterpolatePixelsMain() { delete out_temp; delete engine; } const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Bayer"); } int InterpolatePixelsMain::is_realtime() { return 1; } NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow) void InterpolatePixelsMain::update_gui() { if(thread) { int changed = load_configuration(); if(changed) { thread->window->lock_window("InterpolatePixelsMain::update_gui"); ((InterpolatePixelsWindow*)thread->window)->x_offset->update(config.x); ((InterpolatePixelsWindow*)thread->window)->y_offset->update(config.y); thread->window->unlock_window(); } } } LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig) void InterpolatePixelsMain::save_data(KeyFrame *keyframe) { FileXML output; // cause data to be stored directly in text output.set_shared_output(keyframe->xbuf); output.tag.set_title("INTERPOLATEPIXELS"); output.tag.set_property("X", config.x); output.tag.set_property("Y", config.y); output.append_tag(); output.tag.set_title("/INTERPOLATEPIXELS"); output.append_tag(); output.append_newline(); output.terminate_string(); } void InterpolatePixelsMain::read_data(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->xbuf); int result = 0; while(!result) { result = input.read_tag(); if(!result) { if(input.tag.title_is("INTERPOLATEPIXELS")) { config.x = input.tag.get_property("X", config.x); config.y = input.tag.get_property("Y", config.y); } } } } int InterpolatePixelsMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate) { load_configuration(); // Set aggregation parameters frame->get_params()->update("INTERPOLATEPIXELS_X", config.x); frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y); read_frame(frame, 0, start_position, frame_rate, get_use_opengl()); //frame->dump_params(); if(get_use_opengl()) { // Aggregate with gamma if(next_effect_is(_("Gamma")) || next_effect_is(_("Histogram")) || next_effect_is(_("Color Balance"))) return 0; return run_opengl(); } int color_model = frame->get_color_model(); int active_model = BC_CModels::has_alpha(color_model) ? BC_RGBA_FLOAT : BC_RGB_FLOAT; new_temp(frame->get_w(), frame->get_h(), active_model); get_temp()->transfer_from(frame); out_frame = get_output(); color_model = out_frame->get_color_model(); active_model = BC_CModels::has_alpha(color_model) ? BC_RGBA_FLOAT : BC_RGB_FLOAT; if( active_model != color_model ) { int w = out_frame->get_w(), h = out_frame->get_h(); if( out_temp && ( out_temp->get_color_model() != active_model || out_temp->get_w() != w || out_temp->get_w() != h ) ) { delete out_temp; out_temp = 0; } if( !out_temp ) out_temp = new VFrame(w, h, active_model, 0); out_frame = out_temp; } if(!engine) engine = new InterpolatePixelsEngine(this); engine->process_packages(); if( out_frame != get_output() ) { if( BC_CModels::has_alpha(out_frame->get_color_model()) ) { unsigned char **out_rows = out_frame->get_rows(); int w = out_frame->get_w(), h = out_frame->get_h(); if( BC_CModels::has_alpha(get_temp()->get_color_model()) ) { unsigned char **in_rows = get_temp()->get_rows(); for( int y=0; ytransfer_from(out_frame); } return 0; } // The pattern is // G B // R G // And is offset to recreate the 4 possibilities. // The color values are interpolated in the most basic way. // No adaptive algorithm is used. int InterpolatePixelsMain::handle_opengl() { //printf("InterpolatePixelsMain::handle_opengl\n"); #ifdef HAVE_GL get_output()->to_texture(); get_output()->enable_opengl(); const char *shader_stack[16]; memset(shader_stack,0, sizeof(shader_stack)); int current_shader = 0; INTERPOLATE_COMPILE(shader_stack, current_shader); shader_stack[current_shader] = 0; unsigned int shader = VFrame::make_shader(shader_stack); if( shader > 0 ) { glUseProgram(shader); glUniform1i(glGetUniformLocation(shader, "tex"), 0); INTERPOLATE_UNIFORMS(shader); } get_output()->init_screen(); get_output()->bind_texture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); get_output()->draw_texture(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(0); get_output()->set_opengl_state(VFrame::SCREEN); #endif return 0; } InterpolatePixelsPackage::InterpolatePixelsPackage() : LoadPackage() { } InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin) : LoadClient(server) { this->plugin = plugin; this->server = server; } void InterpolatePixelsUnit::process_package(LoadPackage *package) { InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package; int h = plugin->get_temp()->get_h(); int w = plugin->get_temp()->get_w(); int pattern_offset_x = plugin->config.x; int pattern_offset_y = plugin->config.y; int y1 = pkg->y1; int y2 = pkg->y2; int components = BC_CModels::components(plugin->out_frame->get_color_model()); float color_matrix[9]; memcpy(color_matrix, server->color_matrix, sizeof(color_matrix)); // printf("InterpolatePixelsUnit::process_package %d color_matrix=", __LINE__); // for(int i = 0; i < 9; i++) // { // printf("%f ", color_matrix[i]); // } // printf("\n"); y1 = MAX(y1, 1); y2 = MIN(y2, h - 1); // Only supports float because it's useless in any other colormodel. for(int i = y1; i < y2; i++) { int pattern_coord_y = (i - pattern_offset_y) % 2; float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1]; float *current_row = (float*)plugin->get_temp()->get_rows()[i]; float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1]; float *out_row = (float*)plugin->out_frame->get_rows()[i]; prev_row += components; current_row += components; next_row += components; out_row += components; float r; float g; float b; #undef RED #define RED 0 #undef GREEN #define GREEN 1 #undef BLUE #define BLUE 2 if(pattern_coord_y == 0) { for(int j = 1; j < w - 1; j++) { int pattern_coord_x = (j - pattern_offset_x) % 2; // Top left pixel if(pattern_coord_x == 0) { r = (prev_row[RED] + next_row[RED]) / 2; g = current_row[GREEN]; b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2; } else // Top right pixel { r = (prev_row[-components + RED] + prev_row[components + RED] + next_row[-components + RED] + next_row[components + RED]) / 4; g = (current_row[-components + GREEN] + prev_row[GREEN] + current_row[components + GREEN] + next_row[GREEN]) / 4; b = current_row[BLUE]; } // out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2]; // out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5]; // out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8]; out_row[0] = r; out_row[1] = g; out_row[2] = b; prev_row += components; current_row += components; next_row += components; out_row += components; } } else { for(int j = 1; j < w - 1; j++) { int pattern_coord_x = (j - pattern_offset_x) % 2; // Bottom left pixel if(pattern_coord_x == 0) { r = current_row[RED]; g = (current_row[-components + GREEN] + prev_row[GREEN] + current_row[components + GREEN] + next_row[GREEN]) / 4; b = (prev_row[-components + BLUE] + prev_row[components + BLUE] + next_row[-components + BLUE] + next_row[components + BLUE]) / 4; } else // Bottom right pixel { r = (current_row[-components + RED] + current_row[components + RED]) / 2; g = current_row[GREEN]; b = (prev_row[BLUE] + next_row[BLUE]) / 2; } // out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2]; // out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5]; // out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8]; out_row[0] = r; out_row[1] = g; out_row[2] = b; prev_row += components; current_row += components; next_row += components; out_row += components; } } } } InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin) : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1) { this->plugin = plugin; } void InterpolatePixelsEngine::init_packages() { for( int i=0; i<9; ++i ) color_matrix[i] = 0; for( int i=0; i<3; ++i ) color_matrix[i*3 + i] = 1; char string[BCTEXTLEN]; string[0] = 0; plugin->get_output()->get_params()->get("DCRAW_MATRIX", string); // printf("InterpolatePixelsEngine::init_packages %d\n", __LINE__); // plugin->get_output()->dump_params(); sscanf(string, "%f %f %f %f %f %f %f %f %f", &color_matrix[0], &color_matrix[1], &color_matrix[2], &color_matrix[3], &color_matrix[4], &color_matrix[5], &color_matrix[6], &color_matrix[7], &color_matrix[8]); for(int i = 0; i < get_total_packages(); i++) { InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i); package->y1 = plugin->get_temp()->get_h() * i / get_total_packages(); package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages(); } } LoadClient* InterpolatePixelsEngine::new_client() { return new InterpolatePixelsUnit(this, plugin); } LoadPackage* InterpolatePixelsEngine::new_package() { return new InterpolatePixelsPackage; }