e7133ab1122307565a1e87c9e06138e656f5450b
[goodguy/history.git] / cinelerra-5.1 / 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 "bccmodels.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         out_temp = out_frame = 0;
161         engine = 0;
162 }
163
164 InterpolatePixelsMain::~InterpolatePixelsMain()
165 {
166         delete out_temp;
167         delete engine;
168 }
169
170 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Bayer"); }
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.tag.set_title("/INTERPOLATEPIXELS");
207         output.append_tag();
208         output.append_newline();
209         output.terminate_string();
210 }
211
212 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
213 {
214         FileXML input;
215
216         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
217
218         int result = 0;
219
220         while(!result)
221         {
222                 result = input.read_tag();
223
224                 if(!result)
225                 {
226                         if(input.tag.title_is("INTERPOLATEPIXELS"))
227                         {
228                                 config.x = input.tag.get_property("X", config.x);
229                                 config.y = input.tag.get_property("Y", config.y);
230                         }
231                 }
232         }
233 }
234
235 int InterpolatePixelsMain::process_buffer(VFrame *frame,
236         int64_t start_position,
237         double frame_rate)
238 {
239         load_configuration();
240
241 // Set aggregation parameters
242         frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
243         frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
244
245         read_frame(frame,
246                 0,
247                 start_position,
248                 frame_rate,
249                 get_use_opengl());
250 //frame->dump_params();
251
252         if(get_use_opengl())
253         {
254 // Aggregate with gamma
255                 if(next_effect_is(_("Gamma")) ||
256                         next_effect_is(_("Histogram")) ||
257                         next_effect_is(_("Color Balance")))
258                         return 0;
259
260
261                 return run_opengl();
262         }
263
264         int color_model = frame->get_color_model();
265         int active_model = BC_CModels::has_alpha(color_model) ?
266                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
267         new_temp(frame->get_w(), frame->get_h(), active_model);
268         get_temp()->transfer_from(frame);
269
270         out_frame = get_output();
271         color_model = out_frame->get_color_model();
272         active_model = BC_CModels::has_alpha(color_model) ?
273                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
274         if( active_model != color_model ) {
275                 int w = out_frame->get_w(), h = out_frame->get_h();
276                 if( out_temp && ( out_temp->get_color_model() != active_model ||
277                              out_temp->get_w() != w || out_temp->get_w() != h ) ) {
278                         delete out_temp;  out_temp = 0;
279                 }
280                 if( !out_temp )
281                         out_temp = new VFrame(w, h, active_model, 0);
282                 out_frame = out_temp;
283         }
284
285         if(!engine)
286                 engine = new InterpolatePixelsEngine(this);
287         engine->process_packages();
288
289         if( out_frame != get_output() ) {
290                 if( BC_CModels::has_alpha(out_frame->get_color_model()) ) {
291                         unsigned char **out_rows = out_frame->get_rows();
292                         int w = out_frame->get_w(), h = out_frame->get_h();
293                         if( BC_CModels::has_alpha(get_temp()->get_color_model()) ) {
294                                 unsigned char **in_rows = get_temp()->get_rows();
295                                 for( int y=0; y<h; ++y ) {
296                                         float *inp = (float *)in_rows[y];
297                                         float *outp = (float *)out_rows[y];
298                                         for( int x=0; x<w; ++x,inp+=4,outp+=4 ) outp[3] = inp[3];
299                                 }
300                         }
301                         else {
302                                 for( int y=0; y<h; ++y ) {
303                                         float *outp = (float *)out_rows[y];
304                                         for( int x=0; x<w; ++x,outp+=4 ) outp[3] = 1;
305                                 }
306                         }
307                 }
308                 get_output()->transfer_from(out_frame);
309         }
310
311         return 0;
312 }
313
314 // The pattern is
315 //   G B
316 //   R G
317 // And is offset to recreate the 4 possibilities.
318 // The color values are interpolated in the most basic way.
319 // No adaptive algorithm is used.
320
321 int InterpolatePixelsMain::handle_opengl()
322 {
323 //printf("InterpolatePixelsMain::handle_opengl\n");
324 #ifdef HAVE_GL
325
326
327         get_output()->to_texture();
328         get_output()->enable_opengl();
329
330         const char *shader_stack[16];
331         memset(shader_stack,0, sizeof(shader_stack));
332         int current_shader = 0;
333
334         INTERPOLATE_COMPILE(shader_stack, current_shader);
335
336         shader_stack[current_shader] = 0;
337         unsigned int shader = VFrame::make_shader(shader_stack);
338         if( shader > 0 ) {
339                 glUseProgram(shader);
340                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
341                 INTERPOLATE_UNIFORMS(shader);
342         }
343
344         get_output()->init_screen();
345         get_output()->bind_texture(0);
346         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
347         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
348
349
350         get_output()->draw_texture();
351         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
352         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
353         glUseProgram(0);
354         get_output()->set_opengl_state(VFrame::SCREEN);
355
356 #endif
357         return 0;
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372 InterpolatePixelsPackage::InterpolatePixelsPackage()
373  : LoadPackage()
374 {
375
376 }
377
378
379
380
381
382
383 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
384  : LoadClient(server)
385 {
386         this->plugin = plugin;
387         this->server = server;
388 }
389
390 void InterpolatePixelsUnit::process_package(LoadPackage *package)
391 {
392         InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package;
393         int h = plugin->get_temp()->get_h();
394         int w = plugin->get_temp()->get_w();
395         int pattern_offset_x = plugin->config.x;
396         int pattern_offset_y = plugin->config.y;
397         int y1 = pkg->y1;
398         int y2 = pkg->y2;
399         int components = BC_CModels::components(plugin->out_frame->get_color_model());
400         float color_matrix[9];
401         memcpy(color_matrix, server->color_matrix, sizeof(color_matrix));
402
403 // printf("InterpolatePixelsUnit::process_package %d color_matrix=", __LINE__);
404 // for(int i = 0; i < 9; i++)
405 // {
406 //      printf("%f ", color_matrix[i]);
407 // }
408 // printf("\n");
409
410         y1 = MAX(y1, 1);
411         y2 = MIN(y2, h - 1);
412
413 // Only supports float because it's useless in any other colormodel.
414         for(int i = y1; i < y2; i++)
415         {
416                 int pattern_coord_y = (i - pattern_offset_y) % 2;
417                 float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1];
418                 float *current_row = (float*)plugin->get_temp()->get_rows()[i];
419                 float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1];
420                 float *out_row = (float*)plugin->out_frame->get_rows()[i];
421
422                 prev_row += components;
423                 current_row += components;
424                 next_row += components;
425                 out_row += components;
426                 float r;
427                 float g;
428                 float b;
429 #undef RED
430 #define RED 0
431 #undef GREEN
432 #define GREEN 1
433 #undef BLUE
434 #define BLUE 2
435                 if(pattern_coord_y == 0)
436                 {
437                         for(int j = 1; j < w - 1; j++)
438                         {
439                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
440 // Top left pixel
441                                 if(pattern_coord_x == 0)
442                                 {
443                                         r = (prev_row[RED] + next_row[RED]) / 2;
444                                         g = current_row[GREEN];
445                                         b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2;
446                                 }
447                                 else
448 // Top right pixel
449                                 {
450                                         r = (prev_row[-components + RED] +
451                                                 prev_row[components + RED] +
452                                                 next_row[-components + RED] +
453                                                 next_row[components + RED]) / 4;
454                                         g = (current_row[-components + GREEN] +
455                                                 prev_row[GREEN] +
456                                                 current_row[components + GREEN] +
457                                                 next_row[GREEN]) / 4;
458                                         b = current_row[BLUE];
459                                 }
460
461 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
462 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
463 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
464
465                                 out_row[0] = r;
466                                 out_row[1] = g;
467                                 out_row[2] = b;
468
469                                 prev_row += components;
470                                 current_row += components;
471                                 next_row += components;
472                                 out_row += components;
473                         }
474                 }
475                 else
476                 {
477                         for(int j = 1; j < w - 1; j++)
478                         {
479                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
480 // Bottom left pixel
481                                 if(pattern_coord_x == 0)
482                                 {
483                                         r = current_row[RED];
484                                         g = (current_row[-components + GREEN] +
485                                                 prev_row[GREEN] +
486                                                 current_row[components + GREEN] +
487                                                 next_row[GREEN]) / 4;
488                                         b = (prev_row[-components + BLUE] +
489                                                 prev_row[components + BLUE] +
490                                                 next_row[-components + BLUE] +
491                                                 next_row[components + BLUE]) / 4;
492                                 }
493                                 else
494 // Bottom right pixel
495                                 {
496                                         r = (current_row[-components + RED] + current_row[components + RED]) / 2;
497                                         g = current_row[GREEN];
498                                         b = (prev_row[BLUE] + next_row[BLUE]) / 2;
499                                 }
500
501 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
502 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
503 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
504
505                                 out_row[0] = r;
506                                 out_row[1] = g;
507                                 out_row[2] = b;
508
509                                 prev_row += components;
510                                 current_row += components;
511                                 next_row += components;
512                                 out_row += components;
513                         }
514                 }
515         }
516 }
517
518
519
520
521 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
522  : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
523 {
524         this->plugin = plugin;
525 }
526
527 void InterpolatePixelsEngine::init_packages()
528 {
529         for( int i=0; i<9; ++i ) color_matrix[i] = 0;
530         for( int i=0; i<3; ++i ) color_matrix[i*3 + i] = 1;
531         char string[BCTEXTLEN];
532         string[0] = 0;
533         plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
534
535 // printf("InterpolatePixelsEngine::init_packages %d\n", __LINE__);
536 // plugin->get_output()->dump_params();
537
538         sscanf(string,
539                 "%f %f %f %f %f %f %f %f %f",
540                 &color_matrix[0],
541                 &color_matrix[1],
542                 &color_matrix[2],
543                 &color_matrix[3],
544                 &color_matrix[4],
545                 &color_matrix[5],
546                 &color_matrix[6],
547                 &color_matrix[7],
548                 &color_matrix[8]);
549         for(int i = 0; i < get_total_packages(); i++)
550         {
551                 InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i);
552                 package->y1 = plugin->get_temp()->get_h() * i / get_total_packages();
553                 package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages();
554         }
555 }
556
557
558 LoadClient* InterpolatePixelsEngine::new_client()
559 {
560         return new InterpolatePixelsUnit(this, plugin);
561 }
562
563
564 LoadPackage* InterpolatePixelsEngine::new_package()
565 {
566         return new InterpolatePixelsPackage;
567 }
568
569