05c8565cbf5afe18f667fc9a19f1dcca411d9352
[goodguy/cinelerra.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         xS(50),
49         yS(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         xS(200),
78         yS(100),
79         xS(200),
80         yS(100),
81         0)
82 {
83         this->client = client;
84 }
85
86 InterpolatePixelsWindow::~InterpolatePixelsWindow()
87 {
88 }
89
90 void InterpolatePixelsWindow::create_objects()
91 {
92         int xs5 = xS(5), xs10 = xS(10), xs50 = xS(50);
93         int ys5 = yS(5), ys10 = yS(10);
94         int x = xs10, y = ys10;
95
96         BC_Title *title;
97         add_tool(title = new BC_Title(x, y, _("X Offset:")));
98         add_tool(x_offset = new InterpolatePixelsOffset(this,
99                 x + title->get_w() + xs5,
100                 y,
101                 &client->config.x));
102         y += MAX(x_offset->get_h(), title->get_h()) + ys5;
103         add_tool(title = new BC_Title(x, y, _("Y Offset:")));
104         add_tool(y_offset = new InterpolatePixelsOffset(this,
105                 x + title->get_w() + xs5,
106                 y,
107                 &client->config.y));
108         y += MAX(y_offset->get_h(), title->get_h()) + ys5;
109
110         show_window();
111 }
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 InterpolatePixelsConfig::InterpolatePixelsConfig()
128 {
129         x = 0;
130         y = 0;
131 }
132
133 int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that)
134 {
135         return x == that.x && y == that.y;
136 }
137
138 void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that)
139 {
140         x = that.x;
141         y = that.y;
142 }
143
144 void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev,
145     InterpolatePixelsConfig &next,
146     int64_t prev_position,
147     int64_t next_position,
148     int64_t current_position)
149 {
150     this->x = prev.x;
151     this->y = prev.y;
152 }
153
154
155
156
157
158
159 InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server)
160  : PluginVClient(server)
161 {
162         out_temp = out_frame = 0;
163         engine = 0;
164 }
165
166 InterpolatePixelsMain::~InterpolatePixelsMain()
167 {
168         delete out_temp;
169         delete engine;
170 }
171
172 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Bayer"); }
173 int InterpolatePixelsMain::is_realtime() { return 1; }
174
175
176 NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow)
177
178
179 void InterpolatePixelsMain::update_gui()
180 {
181         if(thread)
182         {
183                 int changed = load_configuration();
184                 if(changed)
185                 {
186                         thread->window->lock_window("InterpolatePixelsMain::update_gui");
187                         ((InterpolatePixelsWindow*)thread->window)->x_offset->update(config.x);
188                         ((InterpolatePixelsWindow*)thread->window)->y_offset->update(config.y);
189                         thread->window->unlock_window();
190                 }
191         }
192 }
193
194
195 LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig)
196
197
198 void InterpolatePixelsMain::save_data(KeyFrame *keyframe)
199 {
200         FileXML output;
201
202 // cause data to be stored directly in text
203         output.set_shared_output(keyframe->xbuf);
204         output.tag.set_title("INTERPOLATEPIXELS");
205         output.tag.set_property("X", config.x);
206         output.tag.set_property("Y", config.y);
207         output.append_tag();
208         output.tag.set_title("/INTERPOLATEPIXELS");
209         output.append_tag();
210         output.append_newline();
211         output.terminate_string();
212 }
213
214 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
215 {
216         FileXML input;
217
218         input.set_shared_input(keyframe->xbuf);
219
220         int result = 0;
221
222         while(!result)
223         {
224                 result = input.read_tag();
225
226                 if(!result)
227                 {
228                         if(input.tag.title_is("INTERPOLATEPIXELS"))
229                         {
230                                 config.x = input.tag.get_property("X", config.x);
231                                 config.y = input.tag.get_property("Y", config.y);
232                         }
233                 }
234         }
235 }
236
237 int InterpolatePixelsMain::process_buffer(VFrame *frame,
238         int64_t start_position,
239         double frame_rate)
240 {
241         load_configuration();
242
243 // Set aggregation parameters
244         frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
245         frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
246
247         read_frame(frame,
248                 0,
249                 start_position,
250                 frame_rate,
251                 get_use_opengl());
252 //frame->dump_params();
253
254         if(get_use_opengl())
255         {
256 // Aggregate with gamma
257                 if(next_effect_is(_("Gamma")) ||
258                         next_effect_is(_("Histogram")) ||
259                         next_effect_is(_("Color Balance")))
260                         return 0;
261
262
263                 return run_opengl();
264         }
265
266         int color_model = frame->get_color_model();
267         int active_model = BC_CModels::has_alpha(color_model) ?
268                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
269         new_temp(frame->get_w(), frame->get_h(), active_model);
270         get_temp()->transfer_from(frame);
271
272         out_frame = get_output();
273         color_model = out_frame->get_color_model();
274         active_model = BC_CModels::has_alpha(color_model) ?
275                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
276         if( active_model != color_model ) {
277                 int w = out_frame->get_w(), h = out_frame->get_h();
278                 if( out_temp && ( out_temp->get_color_model() != active_model ||
279                              out_temp->get_w() != w || out_temp->get_w() != h ) ) {
280                         delete out_temp;  out_temp = 0;
281                 }
282                 if( !out_temp )
283                         out_temp = new VFrame(w, h, active_model, 0);
284                 out_frame = out_temp;
285         }
286
287         if(!engine)
288                 engine = new InterpolatePixelsEngine(this);
289         engine->process_packages();
290
291         if( out_frame != get_output() ) {
292                 if( BC_CModels::has_alpha(out_frame->get_color_model()) ) {
293                         unsigned char **out_rows = out_frame->get_rows();
294                         int w = out_frame->get_w(), h = out_frame->get_h();
295                         if( BC_CModels::has_alpha(get_temp()->get_color_model()) ) {
296                                 unsigned char **in_rows = get_temp()->get_rows();
297                                 for( int y=0; y<h; ++y ) {
298                                         float *inp = (float *)in_rows[y];
299                                         float *outp = (float *)out_rows[y];
300                                         for( int x=0; x<w; ++x,inp+=4,outp+=4 ) outp[3] = inp[3];
301                                 }
302                         }
303                         else {
304                                 for( int y=0; y<h; ++y ) {
305                                         float *outp = (float *)out_rows[y];
306                                         for( int x=0; x<w; ++x,outp+=4 ) outp[3] = 1;
307                                 }
308                         }
309                 }
310                 get_output()->transfer_from(out_frame);
311         }
312
313         return 0;
314 }
315
316 // The pattern is
317 //   G B
318 //   R G
319 // And is offset to recreate the 4 possibilities.
320 // The color values are interpolated in the most basic way.
321 // No adaptive algorithm is used.
322
323 int InterpolatePixelsMain::handle_opengl()
324 {
325 //printf("InterpolatePixelsMain::handle_opengl\n");
326 #ifdef HAVE_GL
327
328
329         get_output()->to_texture();
330         get_output()->enable_opengl();
331
332         const char *shader_stack[16];
333         memset(shader_stack,0, sizeof(shader_stack));
334         int current_shader = 0;
335
336         INTERPOLATE_COMPILE(shader_stack, current_shader);
337
338         shader_stack[current_shader] = 0;
339         unsigned int shader = VFrame::make_shader(shader_stack);
340         if( shader > 0 ) {
341                 glUseProgram(shader);
342                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
343                 INTERPOLATE_UNIFORMS(shader);
344         }
345
346         get_output()->init_screen();
347         get_output()->bind_texture(0);
348         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
349         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
350
351
352         get_output()->draw_texture();
353         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
354         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
355         glUseProgram(0);
356         get_output()->set_opengl_state(VFrame::SCREEN);
357
358 #endif
359         return 0;
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 InterpolatePixelsPackage::InterpolatePixelsPackage()
375  : LoadPackage()
376 {
377
378 }
379
380
381
382
383
384
385 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
386  : LoadClient(server)
387 {
388         this->plugin = plugin;
389         this->server = server;
390 }
391
392 void InterpolatePixelsUnit::process_package(LoadPackage *package)
393 {
394         InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package;
395         int h = plugin->get_temp()->get_h();
396         int w = plugin->get_temp()->get_w();
397         int pattern_offset_x = plugin->config.x;
398         int pattern_offset_y = plugin->config.y;
399         int y1 = pkg->y1;
400         int y2 = pkg->y2;
401         int components = BC_CModels::components(plugin->out_frame->get_color_model());
402         float color_matrix[9];
403         memcpy(color_matrix, server->color_matrix, sizeof(color_matrix));
404
405 // printf("InterpolatePixelsUnit::process_package %d color_matrix=", __LINE__);
406 // for(int i = 0; i < 9; i++)
407 // {
408 //      printf("%f ", color_matrix[i]);
409 // }
410 // printf("\n");
411
412         y1 = MAX(y1, 1);
413         y2 = MIN(y2, h - 1);
414
415 // Only supports float because it's useless in any other colormodel.
416         for(int i = y1; i < y2; i++)
417         {
418                 int pattern_coord_y = (i - pattern_offset_y) % 2;
419                 float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1];
420                 float *current_row = (float*)plugin->get_temp()->get_rows()[i];
421                 float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1];
422                 float *out_row = (float*)plugin->out_frame->get_rows()[i];
423
424                 prev_row += components;
425                 current_row += components;
426                 next_row += components;
427                 out_row += components;
428                 float r;
429                 float g;
430                 float b;
431 #undef RED
432 #define RED 0
433 #undef GREEN
434 #define GREEN 1
435 #undef BLUE
436 #define BLUE 2
437                 if(pattern_coord_y == 0)
438                 {
439                         for(int j = 1; j < w - 1; j++)
440                         {
441                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
442 // Top left pixel
443                                 if(pattern_coord_x == 0)
444                                 {
445                                         r = (prev_row[RED] + next_row[RED]) / 2;
446                                         g = current_row[GREEN];
447                                         b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2;
448                                 }
449                                 else
450 // Top right pixel
451                                 {
452                                         r = (prev_row[-components + RED] +
453                                                 prev_row[components + RED] +
454                                                 next_row[-components + RED] +
455                                                 next_row[components + RED]) / 4;
456                                         g = (current_row[-components + GREEN] +
457                                                 prev_row[GREEN] +
458                                                 current_row[components + GREEN] +
459                                                 next_row[GREEN]) / 4;
460                                         b = current_row[BLUE];
461                                 }
462
463 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
464 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
465 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
466
467                                 out_row[0] = r;
468                                 out_row[1] = g;
469                                 out_row[2] = b;
470
471                                 prev_row += components;
472                                 current_row += components;
473                                 next_row += components;
474                                 out_row += components;
475                         }
476                 }
477                 else
478                 {
479                         for(int j = 1; j < w - 1; j++)
480                         {
481                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
482 // Bottom left pixel
483                                 if(pattern_coord_x == 0)
484                                 {
485                                         r = current_row[RED];
486                                         g = (current_row[-components + GREEN] +
487                                                 prev_row[GREEN] +
488                                                 current_row[components + GREEN] +
489                                                 next_row[GREEN]) / 4;
490                                         b = (prev_row[-components + BLUE] +
491                                                 prev_row[components + BLUE] +
492                                                 next_row[-components + BLUE] +
493                                                 next_row[components + BLUE]) / 4;
494                                 }
495                                 else
496 // Bottom right pixel
497                                 {
498                                         r = (current_row[-components + RED] + current_row[components + RED]) / 2;
499                                         g = current_row[GREEN];
500                                         b = (prev_row[BLUE] + next_row[BLUE]) / 2;
501                                 }
502
503 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
504 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
505 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
506
507                                 out_row[0] = r;
508                                 out_row[1] = g;
509                                 out_row[2] = b;
510
511                                 prev_row += components;
512                                 current_row += components;
513                                 next_row += components;
514                                 out_row += components;
515                         }
516                 }
517         }
518 }
519
520
521
522
523 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
524  : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
525 {
526         this->plugin = plugin;
527 }
528
529 void InterpolatePixelsEngine::init_packages()
530 {
531         for( int i=0; i<9; ++i ) color_matrix[i] = 0;
532         for( int i=0; i<3; ++i ) color_matrix[i*3 + i] = 1;
533         char string[BCTEXTLEN];
534         string[0] = 0;
535         plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
536
537 // printf("InterpolatePixelsEngine::init_packages %d\n", __LINE__);
538 // plugin->get_output()->dump_params();
539
540         sscanf(string,
541                 "%f %f %f %f %f %f %f %f %f",
542                 &color_matrix[0],
543                 &color_matrix[1],
544                 &color_matrix[2],
545                 &color_matrix[3],
546                 &color_matrix[4],
547                 &color_matrix[5],
548                 &color_matrix[6],
549                 &color_matrix[7],
550                 &color_matrix[8]);
551         for(int i = 0; i < get_total_packages(); i++)
552         {
553                 InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i);
554                 package->y1 = plugin->get_temp()->get_h() * i / get_total_packages();
555                 package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages();
556         }
557 }
558
559
560 LoadClient* InterpolatePixelsEngine::new_client()
561 {
562         return new InterpolatePixelsUnit(this, plugin);
563 }
564
565
566 LoadPackage* InterpolatePixelsEngine::new_package()
567 {
568         return new InterpolatePixelsPackage;
569 }
570
571