initial commit
[goodguy/history.git] / cinelerra-5.0 / plugins / interpolate / interpolate.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "colormodels.h"
25 #include "filexml.h"
26 #include "aggregated.h"
27 #include "language.h"
28 #include "interpolate.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33
34 REGISTER_PLUGIN(InterpolatePixelsMain)
35
36
37
38
39
40
41 InterpolatePixelsOffset::InterpolatePixelsOffset(InterpolatePixelsWindow *window, 
42         int x, 
43         int y, 
44         int *output)
45  : BC_ISlider(x,
46         y,
47         0,
48         50,
49         50,
50         0,
51         1,
52         *output,
53         0)
54 {
55         this->window = window;
56         this->output = output;
57 }
58
59 InterpolatePixelsOffset::~InterpolatePixelsOffset()
60 {
61 }
62
63 int InterpolatePixelsOffset::handle_event()
64 {
65         *output = get_value();
66         window->client->send_configure_change();
67         return 1;
68 }
69
70
71
72
73
74
75 InterpolatePixelsWindow::InterpolatePixelsWindow(InterpolatePixelsMain *client)
76  : PluginClientWindow(client,
77         200, 
78         100, 
79         200, 
80         100, 
81         0)
82
83         this->client = client; 
84 }
85
86 InterpolatePixelsWindow::~InterpolatePixelsWindow()
87 {
88 }
89
90 void InterpolatePixelsWindow::create_objects()
91 {
92         int x = 10, y = 10;
93         
94         BC_Title *title;
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,
98                 y, 
99                 &client->config.x));
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,
104                 y, 
105                 &client->config.y));
106         y += MAX(y_offset->get_h(), title->get_h()) + 5;
107
108         show_window();
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 InterpolatePixelsConfig::InterpolatePixelsConfig()
126 {
127         x = 0;
128         y = 0;
129 }
130
131 int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that)
132 {
133         return x == that.x && y == that.y;
134 }
135
136 void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that)
137 {
138         x = that.x;
139         y = that.y;
140 }
141
142 void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev,
143     InterpolatePixelsConfig &next,
144     int64_t prev_position,
145     int64_t next_position,
146     int64_t current_position)
147 {
148     this->x = prev.x;
149     this->y = prev.y;
150 }
151
152
153
154
155
156
157 InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server)
158  : PluginVClient(server)
159 {
160         
161         engine = 0;
162 }
163
164 InterpolatePixelsMain::~InterpolatePixelsMain()
165 {
166         
167         delete engine;
168 }
169
170 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Pixels"); }
171 int InterpolatePixelsMain::is_realtime() { return 1; }
172
173
174 NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow)
175
176
177 void InterpolatePixelsMain::update_gui()
178 {
179         if(thread)
180         {
181                 int changed = load_configuration();
182                 if(changed)
183                 {
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();
188                 }
189         }
190 }
191
192
193 LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig)
194
195
196 void InterpolatePixelsMain::save_data(KeyFrame *keyframe)
197 {
198         FileXML output;
199
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);
205         output.append_tag();
206         output.terminate_string();
207 }
208
209 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
210 {
211         FileXML input;
212
213         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
214
215         int result = 0;
216
217         while(!result)
218         {
219                 result = input.read_tag();
220
221                 if(!result)
222                 {
223                         if(input.tag.title_is("INTERPOLATEPIXELS"))
224                         {
225                                 config.x = input.tag.get_property("X", config.x);
226                                 config.y = input.tag.get_property("Y", config.y);
227                         }
228                 }
229         }
230 }
231
232
233
234 int InterpolatePixelsMain::process_buffer(VFrame *frame,
235         int64_t start_position,
236         double frame_rate)
237 {
238         load_configuration();
239
240 // Set aggregation parameters
241         frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
242         frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
243
244         read_frame(frame, 
245                 0, 
246                 start_position, 
247                 frame_rate,
248                 get_use_opengl());
249 //frame->dump_params();
250
251         if(get_use_opengl())
252         {
253 // Aggregate with gamma
254                 if(next_effect_is("Gamma") ||
255                         next_effect_is("Histogram") ||
256                         next_effect_is("Color Balance"))
257                         return 0;
258
259
260                 return run_opengl();
261         }
262
263
264         if(get_output()->get_color_model() != BC_RGB_FLOAT &&
265                 get_output()->get_color_model() != BC_RGBA_FLOAT)
266         {
267                 printf("InterpolatePixelsMain::process_buffer: only supports float colormodels\n");
268                 return 1;
269         }
270
271         new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
272         get_temp()->copy_from(frame);
273         if(!engine)
274                 engine = new InterpolatePixelsEngine(this);
275         engine->process_packages();
276
277         return 0;
278 }
279
280 // The pattern is
281 //   G B
282 //   R G
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.
286
287 int InterpolatePixelsMain::handle_opengl()
288 {
289 //printf("InterpolatePixelsMain::handle_opengl\n");
290 #ifdef HAVE_GL
291
292
293         get_output()->to_texture();
294         get_output()->enable_opengl();
295
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,
300                                         shader_stack[0],
301                                         0);
302         if(frag > 0)
303         {
304                 glUseProgram(frag);
305                 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
306                 INTERPOLATE_UNIFORMS(frag)
307         }
308
309
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);
314         
315
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);
319         glUseProgram(0);
320         get_output()->set_opengl_state(VFrame::SCREEN);
321
322 #endif
323         return 0;
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338 InterpolatePixelsPackage::InterpolatePixelsPackage()
339  : LoadPackage()
340 {
341         
342 }
343
344
345
346
347
348
349 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
350  : LoadClient(server)
351 {
352         this->plugin = plugin;
353         this->server = server;
354 }
355
356 void InterpolatePixelsUnit::process_package(LoadPackage *package)
357 {
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;
363         int y1 = pkg->y1;
364         int y2 = pkg->y2;
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));
368
369         y1 = MAX(y1, 1);
370         y2 = MIN(y2, h - 1);
371
372 // Only supports float because it's useless in any other colormodel.
373         for(int i = y1; i < y2; i++)
374         {
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];
380
381                 prev_row += components;
382                 current_row += components;
383                 next_row += components;
384                 out_row += components;
385                 float r;
386                 float g;
387                 float b;
388 #undef RED
389 #define RED 0
390 #undef GREEN
391 #define GREEN 1
392 #undef BLUE
393 #define BLUE 2
394                 if(pattern_coord_y == 0)
395                 {
396                         for(int j = 1; j < w - 1; j++)
397                         {
398                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
399 // Top left pixel
400                                 if(pattern_coord_x == 0)
401                                 {
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;
405                                 }
406                                 else
407 // Top right pixel
408                                 {
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] +
414                                                 prev_row[GREEN] +
415                                                 current_row[components + GREEN] +
416                                                 next_row[GREEN]) / 4;
417                                         b = current_row[BLUE];
418                                 }
419
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;
427                         }
428                 }
429                 else
430                 {
431                         for(int j = 1; j < w - 1; j++)
432                         {
433                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
434 // Bottom left pixel
435                                 if(pattern_coord_x == 0)
436                                 {
437                                         r = current_row[RED];
438                                         g = (current_row[-components + GREEN] +
439                                                 prev_row[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;
446                                 }
447                                 else
448 // Bottom right pixel
449                                 {
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;
453                                 }
454
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;
462                         }
463                 }
464         }
465 }
466
467
468
469
470 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
471  : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
472 {
473         this->plugin = plugin;
474 }
475
476 void InterpolatePixelsEngine::init_packages()
477 {
478         char string[BCTEXTLEN];
479         string[0] = 0;
480         plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
481         sscanf(string, 
482                 "%f %f %f %f %f %f %f %f %f", 
483                 &color_matrix[0],
484                 &color_matrix[1],
485                 &color_matrix[2],
486                 &color_matrix[3],
487                 &color_matrix[4],
488                 &color_matrix[5],
489                 &color_matrix[6],
490                 &color_matrix[7],
491                 &color_matrix[8]);
492         for(int i = 0; i < get_total_packages(); i++)
493         {
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();
497         }
498 }
499
500
501 LoadClient* InterpolatePixelsEngine::new_client()
502 {
503         return new InterpolatePixelsUnit(this, plugin);
504 }
505
506
507 LoadPackage* InterpolatePixelsEngine::new_package()
508 {
509         return new InterpolatePixelsPackage;
510 }
511
512