--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+
+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 _("Interpolate Pixels"); }
+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->get_data(), MESSAGESIZE);
+ 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->get_data(), strlen(keyframe->get_data()));
+
+ 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(0, -1, w, h, active_model, -1);
+ 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; y<h; ++y ) {
+ float *inp = (float *)in_rows[y];
+ float *outp = (float *)out_rows[y];
+ for( int x=0; x<w; ++x,inp+=4,outp+=4 ) outp[3] = inp[3];
+ }
+ }
+ else {
+ for( int y=0; y<h; ++y ) {
+ float *outp = (float *)out_rows[y];
+ for( int x=0; x<w; ++x,outp+=4 ) outp[3] = 1;
+ }
+ }
+ }
+ get_output()->transfer_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[] = { 0, 0, 0 };
+ int current_shader = 0;
+ INTERPOLATE_COMPILE(shader_stack, current_shader)
+ unsigned int frag = VFrame::make_shader(0,
+ shader_stack[0],
+ 0);
+ if(frag > 0)
+ {
+ glUseProgram(frag);
+ glUniform1i(glGetUniformLocation(frag, "tex"), 0);
+ INTERPOLATE_UNIFORMS(frag)
+ }
+
+
+ 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));
+
+ 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];
+ 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];
+ 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);
+ 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;
+}
+
+