add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / holo / holo.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 "clip.h"
23 #include "bccmodels.h"
24 #include "effecttv.h"
25 #include "filexml.h"
26 #include "holo.h"
27 #include "holowindow.h"
28 #include "language.h"
29 #include "bccolors.h"
30
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <string.h>
34
35
36 REGISTER_PLUGIN(HoloMain)
37
38
39
40
41
42
43
44
45
46
47 HoloConfig::HoloConfig()
48 {
49         threshold = 40;
50         recycle = 1.0;
51 }
52
53
54
55
56
57 HoloMain::HoloMain(PluginServer *server)
58  : PluginVClient(server)
59 {
60         effecttv = 0;
61         bgimage = 0;
62         do_reconfigure = 1;
63 }
64
65 HoloMain::~HoloMain()
66 {
67         if(effecttv) {
68                 delete holo_server;
69                 delete effecttv;
70         }
71
72         if(bgimage)
73                 delete bgimage;
74 }
75
76 const char* HoloMain::plugin_title() { return N_("HolographicTV"); }
77 int HoloMain::is_realtime() { return 1; }
78
79 NEW_WINDOW_MACRO(HoloMain, HoloWindow)
80
81 int HoloMain::load_configuration()
82 {
83         return 0;
84 }
85
86
87 void HoloMain::save_data(KeyFrame *keyframe)
88 {
89 }
90
91 void HoloMain::read_data(KeyFrame *keyframe)
92 {
93 }
94
95 void HoloMain::reconfigure()
96 {
97         do_reconfigure = 0;
98
99         effecttv->image_set_threshold_y(config.threshold);
100 }
101
102
103 #define ADD_FRAMES(type, components) \
104 { \
105         type **input_rows = (type**)input->get_rows(); \
106         type **output_rows = (type**)output->get_rows(); \
107         int w = input->get_w(); \
108         int h = input->get_h(); \
109  \
110         for(int i = 0; i < h; i++) \
111         { \
112                 type *output_row = (type*)output_rows[i]; \
113                 type *input_row = (type*)input_rows[i]; \
114  \
115                 for(int j = 0; j < w; j++) \
116                 { \
117                         for(int k = 0; k < 3; k++) \
118                         { \
119                                 if(sizeof(type) == 4) \
120                                 { \
121                                         int in_temp = (int)(*input_row * 0xffff); \
122                                         int out_temp = (int)(*output_row * 0xffff); \
123                                         int temp = (in_temp & out_temp) + \
124                                                 ((in_temp ^ out_temp) >> 1); \
125                                         *output_row = (type)temp / 0xffff; \
126                                 } \
127                                 else \
128                                 { \
129                                         *output_row = ((uint16_t)*input_row & (uint16_t)*output_row) + \
130                                                 (((uint16_t)*input_row ^ (uint16_t)*output_row) >> 1); \
131                                 } \
132                                 output_row++; \
133                                 input_row++; \
134                         } \
135  \
136                         if(components == 4) \
137                         { \
138                                 output_row++; \
139                                 input_row++; \
140                         } \
141                 } \
142         } \
143 }
144
145
146 // Add input to output and store result in output
147 void HoloMain::add_frames(VFrame *output, VFrame *input)
148 {
149         switch(output->get_color_model())
150         {
151                 case BC_RGB888:
152                 case BC_YUV888:
153                         ADD_FRAMES(uint8_t, 3);
154                         break;
155                 case BC_RGB_FLOAT:
156                         ADD_FRAMES(float, 3);
157                         break;
158                 case BC_RGBA_FLOAT:
159                         ADD_FRAMES(float, 4);
160                         break;
161                 case BC_RGBA8888:
162                 case BC_YUVA8888:
163                         ADD_FRAMES(uint8_t, 4);
164                         break;
165                 case BC_RGB161616:
166                 case BC_YUV161616:
167                         ADD_FRAMES(uint16_t, 3);
168                         break;
169                 case BC_RGBA16161616:
170                 case BC_YUVA16161616:
171                         ADD_FRAMES(uint16_t, 4);
172                         break;
173         }
174 }
175
176 void HoloMain::set_background()
177 {
178 /*
179  * grab 4 frames and composite them to get a quality background image
180  */
181 /**
182  * For Cinelerra, we make every frame a holograph and expect the user to
183  * provide a matte.
184  **/
185 total = 0;
186
187         switch(total)
188         {
189                 case 0:
190 /* step 1: grab frame-1 to buffer-1 */
191 //                      tmp = new VFrame(input_ptr->get_w(),input_ptr->get_h(),
192 //                              project_color_model, 0);
193                         bgimage->copy_from(input_ptr);
194                         break;
195
196                 case 1:
197 /* step 2: add frame-2 to buffer-1 */
198                         add_frames(bgimage, input_ptr);
199                         break;
200
201                 case 2:
202 /* step 3: grab frame-3 to buffer-2 */
203                         tmp->copy_from(input_ptr);
204                         break;
205
206                 case 3:
207 /* step 4: add frame-4 to buffer-2 */
208                         add_frames(tmp, input_ptr);
209
210
211
212 /* step 5: add buffer-3 to buffer-1 */
213                         add_frames(bgimage, tmp);
214
215                         effecttv->image_bgset_y(bgimage);
216
217
218                         delete tmp;
219                         break;
220         }
221 }
222
223
224 int HoloMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
225 {
226         this->input_ptr = input_ptr;
227         this->output_ptr = output_ptr;
228
229
230
231
232         load_configuration();
233
234
235
236         if(do_reconfigure)
237         {
238                 if(!effecttv)
239                 {
240                         effecttv = new EffectTV(input_ptr->get_w(), input_ptr->get_h());
241                         bgimage = new VFrame(input_ptr->get_w(), input_ptr->get_h(),
242                                 input_ptr->get_color_model(), 0);
243
244                         for(int i = 0; i < 256; i++)
245                         {
246                                 noisepattern[i] = (i * i * i / 40000)* i / 256;
247                         }
248
249                         holo_server = new HoloServer(this, 1, 1);
250                 }
251
252                 reconfigure();
253         }
254
255         set_background();
256
257         holo_server->process_packages();
258
259         total++;
260         if(total >= config.recycle * project_frame_rate)
261                 total = 0;
262
263         return 0;
264 }
265
266
267
268
269
270 HoloServer::HoloServer(HoloMain *plugin, int total_clients, int total_packages)
271  : LoadServer(total_clients, total_packages)
272 {
273         this->plugin = plugin;
274 }
275
276
277 LoadClient* HoloServer::new_client()
278 {
279         return new HoloClient(this);
280 }
281
282
283
284
285 LoadPackage* HoloServer::new_package()
286 {
287         return new HoloPackage;
288 }
289
290
291
292 void HoloServer::init_packages()
293 {
294         for(int i = 0; i < get_total_packages(); i++)
295         {
296                 HoloPackage *package = (HoloPackage*)get_package(i);
297                 package->row1 = plugin->input_ptr->get_h() * i / get_total_packages();
298                 package->row2 = plugin->input_ptr->get_h() * (i + 1) / get_total_packages();
299         }
300 }
301
302
303
304
305
306
307
308
309 HoloClient::HoloClient(HoloServer *server)
310  : LoadClient(server)
311 {
312         this->plugin = server->plugin;
313         phase = 0;
314 }
315
316
317 void HoloClient::process_package(LoadPackage *package)
318 {
319         int x, y;
320         HoloPackage *local_package = (HoloPackage*)package;
321         unsigned char **input_rows = plugin->input_ptr->get_rows() + local_package->row1;
322         unsigned char **output_rows = plugin->output_ptr->get_rows() + local_package->row1;
323         int width = plugin->input_ptr->get_w();
324         int height = local_package->row2 - local_package->row1;
325         unsigned char *diff;
326         uint32_t s, t;
327         int r, g, b;
328
329         diff = plugin->effecttv->image_diff_filter(plugin->effecttv->image_bgsubtract_y(input_rows,
330                 plugin->input_ptr->get_color_model()));
331
332         diff += width;
333         output_rows++;
334         input_rows++;
335
336
337 // Convert discrete channels to a single 24 bit number
338 #define STORE_PIXEL(type, components, dest, src, is_yuv) \
339 if(sizeof(type) == 4) \
340 { \
341         int r = (int)(src[0] * 0xff); \
342         int g = (int)(src[1] * 0xff); \
343         int b = (int)(src[2] * 0xff); \
344         CLAMP(r, 0, 0xff); \
345         CLAMP(g, 0, 0xff); \
346         CLAMP(b, 0, 0xff); \
347         dest = (r << 16) | (g << 8) | b; \
348 } \
349 else \
350 if(sizeof(type) == 2) \
351 { \
352         if(is_yuv) \
353         { \
354                 int r = (int)src[0] >> 8; \
355                 int g = (int)src[1] >> 8; \
356                 int b = (int)src[2] >> 8; \
357                 YUV::yuv.yuv_to_rgb_8(r, g, b); \
358                 dest = (r << 16) | (g << 8) | b; \
359         } \
360         else \
361         { \
362                 dest = (((uint32_t)src[0] << 8) & 0xff0000) | \
363                         ((uint32_t)src[1] & 0xff00) | \
364                         ((uint32_t)src[2]) >> 8; \
365         } \
366 } \
367 else \
368 { \
369         if(is_yuv) \
370         { \
371                 int r = (int)src[0]; \
372                 int g = (int)src[1]; \
373                 int b = (int)src[2]; \
374                 YUV::yuv.yuv_to_rgb_8(r, g, b); \
375                 dest = (r << 16) | (g << 8) | b; \
376         } \
377         else \
378         { \
379                 dest = ((uint32_t)src[0] << 16) | \
380                         ((uint32_t)src[1] << 8) | \
381                         (uint32_t)src[2]; \
382         } \
383 }
384
385
386
387
388 #define HOLO_CORE(type, components, is_yuv) \
389         for(y = 1; y < height - 1; y++) \
390         { \
391                 type *src = (type*)input_rows[y]; \
392                 type *bg = (type*)plugin->bgimage->get_rows()[y]; \
393                 type *dest = (type*)output_rows[y]; \
394  \
395  \
396  \
397                 if(((y + phase) & 0x7f) < 0x58)  \
398                 { \
399                         for(x = 0 ; x < width; x++)  \
400                         { \
401                                 if(*diff) \
402                                 { \
403                                         STORE_PIXEL(type, components, s, src, is_yuv); \
404  \
405                                         t = (s & 0xff) +  \
406                                                 ((s & 0xff00) >> 7) +  \
407                                                 ((s & 0xff0000) >> 16); \
408                                         t += plugin->noisepattern[EffectTV::fastrand() >> 24]; \
409  \
410                                         r = ((s & 0xff0000) >> 17) + t; \
411                                         g = ((s & 0xff00) >> 8) + t; \
412                                         b = (s & 0xff) + t; \
413  \
414                                         r = (r >> 1) - 100; \
415                                         g = (g >> 1) - 100; \
416                                         b = b >> 2; \
417  \
418                                         if(r < 20) r = 20; \
419                                         if(g < 20) g = 20; \
420  \
421                                         STORE_PIXEL(type, components, s, bg, is_yuv); \
422  \
423                                         r += (s & 0xff0000) >> 17; \
424                                         g += (s & 0xff00) >> 9; \
425                                         b += ((s & 0xff) >> 1) + 40; \
426  \
427                                         if(r > 255) r = 255; \
428                                         if(g > 255) g = 255; \
429                                         if(b > 255) b = 255; \
430  \
431                                         if(is_yuv) YUV::yuv.rgb_to_yuv_8(r, g, b); \
432                                         if(sizeof(type) == 4) \
433                                         { \
434                                                 dest[0] = (type)r / 0xff; \
435                                                 dest[1] = (type)g / 0xff; \
436                                                 dest[2] = (type)b / 0xff; \
437                                         } \
438                                         else \
439                                         if(sizeof(type) == 2) \
440                                         { \
441                                                 dest[0] = (r << 8) | r; \
442                                                 dest[1] = (g << 8) | g; \
443                                                 dest[2] = (b << 8) | b; \
444                                         } \
445                                         else \
446                                         { \
447                                                 dest[0] = r; \
448                                                 dest[1] = g; \
449                                                 dest[2] = b; \
450                                         } \
451                                 }  \
452                                 else  \
453                                 { \
454                                         dest[0] = bg[0]; \
455                                         dest[1] = bg[1]; \
456                                         dest[2] = bg[2]; \
457                                 } \
458  \
459                                 diff++; \
460                                 src += components; \
461                                 dest += components; \
462                                 bg += components; \
463                         } \
464                 }  \
465                 else  \
466                 { \
467                         for(x = 0; x < width; x++) \
468                         { \
469                                 if(*diff) \
470                                 { \
471                                         STORE_PIXEL(type, components, s, src, is_yuv); \
472  \
473  \
474                                         t = (s & 0xff) + ((s & 0xff00) >> 6) + ((s & 0xff0000) >> 16); \
475                                         t += plugin->noisepattern[EffectTV::fastrand() >> 24]; \
476  \
477                                         r = ((s & 0xff0000) >> 16) + t; \
478                                         g = ((s & 0xff00) >> 8) + t; \
479                                         b = (s & 0xff) + t; \
480  \
481                                         r = (r >> 1) - 100; \
482                                         g = (g >> 1) - 100; \
483                                         b = b >> 2; \
484  \
485                                         if(r < 0) r = 0; \
486                                         if(g < 0) g = 0; \
487  \
488                                         STORE_PIXEL(type, components, s, bg, is_yuv); \
489  \
490                                         r += ((s & 0xff0000) >> 17) + 10; \
491                                         g += ((s & 0xff00) >> 9) + 10; \
492                                         b += ((s & 0xff) >> 1) + 40; \
493  \
494                                         if(r > 255) r = 255; \
495                                         if(g > 255) g = 255; \
496                                         if(b > 255) b = 255; \
497  \
498                                         if(is_yuv) YUV::yuv.rgb_to_yuv_8(r, g, b); \
499                                         if(sizeof(type) == 4) \
500                                         { \
501                                                 dest[0] = (type)r / 0xff; \
502                                                 dest[1] = (type)g / 0xff; \
503                                                 dest[2] = (type)b / 0xff; \
504                                         } \
505                                         else \
506                                         if(sizeof(type) == 2) \
507                                         { \
508                                                 dest[0] = (r << 8) | r; \
509                                                 dest[1] = (g << 8) | g; \
510                                                 dest[2] = (b << 8) | b; \
511                                         } \
512                                         else \
513                                         { \
514                                                 dest[0] = r; \
515                                                 dest[1] = g; \
516                                                 dest[2] = b; \
517                                         } \
518                                 }  \
519                                 else  \
520                                 { \
521                                         dest[0] = bg[0]; \
522                                         dest[1] = bg[1]; \
523                                         dest[2] = bg[2]; \
524                                 } \
525  \
526                                 diff++; \
527                                 src += components; \
528                                 dest += components; \
529                                 bg += components; \
530                         } \
531                 } \
532         }
533
534
535
536
537         switch(plugin->input_ptr->get_color_model())
538         {
539                 case BC_RGB888:
540                         HOLO_CORE(uint8_t, 3, 0);
541                         break;
542                 case BC_RGB_FLOAT:
543                         HOLO_CORE(float, 3, 0);
544                         break;
545                 case BC_YUV888:
546                         HOLO_CORE(uint8_t, 3, 1);
547                         break;
548                 case BC_RGBA_FLOAT:
549                         HOLO_CORE(float, 4, 0);
550                         break;
551                 case BC_RGBA8888:
552                         HOLO_CORE(uint8_t, 4, 0);
553                         break;
554                 case BC_YUVA8888:
555                         HOLO_CORE(uint8_t, 4, 1);
556                         break;
557                 case BC_RGB161616:
558                         HOLO_CORE(uint16_t, 3, 0);
559                         break;
560                 case BC_YUV161616:
561                         HOLO_CORE(uint16_t, 3, 1);
562                         break;
563                 case BC_RGBA16161616:
564                         HOLO_CORE(uint16_t, 4, 0);
565                         break;
566                 case BC_YUVA16161616:
567                         HOLO_CORE(uint16_t, 4, 1);
568                         break;
569         }
570
571
572
573         phase -= 37;
574 }
575
576
577
578 HoloPackage::HoloPackage()
579 {
580 }
581
582
583