prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / maskengine.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 "bcsignals.h"
23 #include "condition.h"
24 #include "clip.h"
25 #include "maskauto.h"
26 #include "maskautos.h"
27 #include "maskengine.h"
28 #include "mutex.h"
29 #include "transportque.inc"
30 #include "vframe.h"
31
32 #include <math.h>
33 #include <stdint.h>
34 #include <string.h>
35
36 MaskPackage::MaskPackage()
37 {
38 }
39
40 MaskPackage::~MaskPackage()
41 {
42 }
43
44
45
46
47
48
49
50 MaskUnit::MaskUnit(MaskEngine *engine)
51  : LoadClient(engine)
52 {
53         this->engine = engine;
54         this->temp = 0;
55 }
56
57
58 MaskUnit::~MaskUnit()
59 {
60         if(temp) delete temp;
61 }
62
63
64 #define OVERSAMPLE 8
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 void MaskUnit::draw_line_clamped(VFrame *frame, 
82         int &x1, 
83         int &y1, 
84         int x2, 
85         int y2,
86         unsigned char k)
87 {
88         int draw_x1;
89         int draw_y1;
90         int draw_x2;
91         int draw_y2;
92
93         if(y2 < y1)
94         {
95                 draw_x1 = x2;
96                 draw_y1 = y2;
97                 draw_x2 = x1;
98                 draw_y2 = y1;
99         }
100         else
101         {
102                 draw_x1 = x1;
103                 draw_y1 = y1;
104                 draw_x2 = x2;
105                 draw_y2 = y2;
106         }
107
108         unsigned char **rows = (unsigned char**)frame->get_rows();
109
110         if(draw_y2 != draw_y1)
111         {
112                 float slope = ((float)draw_x2 - draw_x1) / ((float)draw_y2 - draw_y1);
113                 int w = frame->get_w() - 1;
114                 int h = frame->get_h();
115
116                 for(float y = draw_y1; y < draw_y2; y++)
117                 {
118                         if(y >= 0 && y < h)
119                         {
120                                 int x = (int)((y - draw_y1) * slope + draw_x1);
121                                 int y_i = (int)y;
122                                 int x_i = CLIP(x, 0, w);
123
124                                 if(rows[y_i][x_i] == k)
125                                         rows[y_i][x_i] = 0;
126                                 else
127                                         rows[y_i][x_i] = k;
128                         }
129                 }
130         }
131 }
132
133 void MaskUnit::blur_strip(double *val_p, 
134         double *val_m, 
135         double *dst, 
136         double *src, 
137         int size,
138         int max)
139 {
140         double *sp_p = src;
141         double *sp_m = src + size - 1;
142         double *vp = val_p;
143         double *vm = val_m + size - 1;
144         double initial_p = sp_p[0];
145         double initial_m = sp_m[0];
146
147 //printf("MaskUnit::blur_strip %d\n", size);
148         for(int k = 0; k < size; k++)
149         {
150                 int terms = (k < 4) ? k : 4;
151                 int l;
152                 for(l = 0; l <= terms; l++)
153                 {
154                         *vp += n_p[l] * sp_p[-l] - d_p[l] * vp[-l];
155                         *vm += n_m[l] * sp_m[l] - d_m[l] * vm[l];
156                 }
157
158                 for( ; l <= 4; l++)
159                 {
160                         *vp += (n_p[l] - bd_p[l]) * initial_p;
161                         *vm += (n_m[l] - bd_m[l]) * initial_m;
162                 }
163                 sp_p++;
164                 sp_m--;
165                 vp++;
166                 vm--;
167         }
168
169         for(int i = 0; i < size; i++)
170         {
171                 double sum = val_p[i] + val_m[i];
172                 CLAMP(sum, 0, max);
173                 dst[i] = sum;
174         }
175 }
176
177 void MaskUnit::do_feather(VFrame *output,
178         VFrame *input, 
179         double feather, 
180         int start_y, 
181         int end_y, 
182         int start_x, 
183         int end_x)
184 {
185 //printf("MaskUnit::do_feather %f\n", feather);
186 // Get constants
187         double constants[8];
188         double div;
189         double std_dev = sqrt(-(double)(feather * feather) / (2 * log(1.0 / 255.0)));
190         div = sqrt(2 * M_PI) * std_dev;
191         constants[0] = -1.783 / std_dev;
192         constants[1] = -1.723 / std_dev;
193         constants[2] = 0.6318 / std_dev;
194         constants[3] = 1.997  / std_dev;
195         constants[4] = 1.6803 / div;
196         constants[5] = 3.735 / div;
197         constants[6] = -0.6803 / div;
198         constants[7] = -0.2598 / div;
199
200         n_p[0] = constants[4] + constants[6];
201         n_p[1] = exp(constants[1]) *
202                                 (constants[7] * sin(constants[3]) -
203                                 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
204                                 exp(constants[0]) *
205                                 (constants[5] * sin(constants[2]) -
206                                 (2 * constants[6] + constants[4]) * cos(constants[2]));
207
208         n_p[2] = 2 * exp(constants[0] + constants[1]) *
209                                 ((constants[4] + constants[6]) * cos(constants[3]) * 
210                                 cos(constants[2]) - constants[5] * 
211                                 cos(constants[3]) * sin(constants[2]) -
212                                 constants[7] * cos(constants[2]) * sin(constants[3])) +
213                                 constants[6] * exp(2 * constants[0]) +
214                                 constants[4] * exp(2 * constants[1]);
215
216         n_p[3] = exp(constants[1] + 2 * constants[0]) *
217                                 (constants[7] * sin(constants[3]) - 
218                                 constants[6] * cos(constants[3])) +
219                                 exp(constants[0] + 2 * constants[1]) *
220                                 (constants[5] * sin(constants[2]) - constants[4] * 
221                                 cos(constants[2]));
222         n_p[4] = 0.0;
223
224         d_p[0] = 0.0;
225         d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
226                                 2 * exp(constants[0]) * cos(constants[2]);
227
228         d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) * 
229                                 exp(constants[0] + constants[1]) +
230                                 exp(2 * constants[1]) + exp (2 * constants[0]);
231
232         d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
233                                 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
234
235         d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
236
237         for(int i = 0; i < 5; i++) d_m[i] = d_p[i];
238
239         n_m[0] = 0.0;
240         for(int i = 1; i <= 4; i++)
241                 n_m[i] = n_p[i] - d_p[i] * n_p[0];
242
243         double sum_n_p, sum_n_m, sum_d;
244         double a, b;
245
246         sum_n_p = 0.0;
247         sum_n_m = 0.0;
248         sum_d = 0.0;
249         for(int i = 0; i < 5; i++)
250         {
251                 sum_n_p += n_p[i];
252                 sum_n_m += n_m[i];
253                 sum_d += d_p[i];
254         }
255
256         a = sum_n_p / (1 + sum_d);
257         b = sum_n_m / (1 + sum_d);
258
259         for(int i = 0; i < 5; i++)
260         {
261                 bd_p[i] = d_p[i] * a;
262                 bd_m[i] = d_m[i] * b;
263         }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 #define DO_FEATHER(type, max) \
287 { \
288         int frame_w = input->get_w(); \
289         int frame_h = input->get_h(); \
290         int size = MAX(frame_w, frame_h); \
291         double *src = new double[size]; \
292         double *dst = new double[size]; \
293         double *val_p = new double[size]; \
294         double *val_m = new double[size]; \
295         type **in_rows = (type**)input->get_rows(); \
296         type **out_rows = (type**)output->get_rows(); \
297         int j; \
298  \
299 /* printf("DO_FEATHER 1\n"); */ \
300         if(end_x > start_x) \
301         { \
302                 for(j = start_x; j < end_x; j++) \
303                 { \
304         /* printf("DO_FEATHER 1.1 %d\n", j); */ \
305                         bzero(val_p, sizeof(double) * frame_h); \
306                         bzero(val_m, sizeof(double) * frame_h); \
307                         for(int k = 0; k < frame_h; k++) \
308                         { \
309                                 src[k] = (double)in_rows[k][j]; \
310                         } \
311          \
312                         blur_strip(val_p, val_m, dst, src, frame_h, max); \
313          \
314                         for(int k = 0; k < frame_h; k++) \
315                         { \
316                                 out_rows[k][j] = (type)dst[k]; \
317                         } \
318                 } \
319         } \
320  \
321         if(end_y > start_y) \
322         { \
323                 for(j = start_y; j < end_y; j++) \
324                 { \
325         /* printf("DO_FEATHER 2 %d\n", j); */ \
326                         bzero(val_p, sizeof(double) * frame_w); \
327                         bzero(val_m, sizeof(double) * frame_w); \
328                         for(int k = 0; k < frame_w; k++) \
329                         { \
330                                 src[k] = (double)out_rows[j][k]; \
331                         } \
332          \
333                         blur_strip(val_p, val_m, dst, src, frame_w, max); \
334          \
335                         for(int k = 0; k < frame_w; k++) \
336                         { \
337                                 out_rows[j][k] = (type)dst[k]; \
338                         } \
339                 } \
340         } \
341  \
342 /* printf("DO_FEATHER 3\n"); */ \
343  \
344         delete [] src; \
345         delete [] dst; \
346         delete [] val_p; \
347         delete [] val_m; \
348 /* printf("DO_FEATHER 4\n"); */ \
349 }
350
351
352
353
354
355
356
357
358 //printf("do_feather %d\n", frame->get_color_model());
359         switch(input->get_color_model())
360         {
361                 case BC_A8:
362                         DO_FEATHER(unsigned char, 0xff);
363                         break;
364                 
365                 case BC_A16:
366                         DO_FEATHER(uint16_t, 0xffff);
367                         break;
368                 
369                 case BC_A_FLOAT:
370                         DO_FEATHER(float, 1);
371                         break;
372         }
373
374
375
376
377 }
378
379 void MaskUnit::process_package(LoadPackage *package)
380 {
381         MaskPackage *ptr = (MaskPackage*)package;
382
383         if(engine->recalculate && 
384                 engine->step == DO_MASK)
385         {
386                 VFrame *mask;
387                 if(engine->feather > 0) 
388                         mask = engine->temp_mask;
389                 else
390                         mask = engine->mask;
391
392 SET_TRACE
393 // Generated oversampling frame
394                 int mask_w = mask->get_w();
395                 //int mask_h = mask->get_h();
396                 int oversampled_package_w = mask_w * OVERSAMPLE;
397                 int oversampled_package_h = (ptr->end_y - ptr->start_y) * OVERSAMPLE;
398 //printf("MaskUnit::process_package 1\n");
399
400 SET_TRACE
401                 if(temp && 
402                         (temp->get_w() != oversampled_package_w ||
403                         temp->get_h() != oversampled_package_h))
404                 {
405                         delete temp;
406                         temp = 0;
407                 }
408 //printf("MaskUnit::process_package 1\n");
409
410 SET_TRACE
411                 if(!temp)
412                 {
413                         temp = new VFrame(0, 
414                                 -1,
415                                 oversampled_package_w, 
416                                 oversampled_package_h,
417                                 BC_A8,
418                                 -1);
419                 }
420
421 SET_TRACE
422                 temp->clear_frame();
423 //printf("MaskUnit::process_package 1 %d\n", engine->point_sets.total);
424
425 SET_TRACE
426
427 // Draw oversampled region of polygons on temp
428                 for(int k = 0; k < engine->point_sets.total; k++)
429                 {
430                         int old_x, old_y;
431                         unsigned char max = k + 1;
432                         ArrayList<MaskPoint*> *points = engine->point_sets.values[k];
433
434                         if(points->total < 3) continue;
435 //printf("MaskUnit::process_package 2 %d %d\n", k, points->total);
436                         for(int i = 0; i < points->total; i++)
437                         {
438                                 MaskPoint *point1 = points->values[i];
439                                 MaskPoint *point2 = (i >= points->total - 1) ? 
440                                         points->values[0] : 
441                                         points->values[i + 1];
442
443                                 float x, y;
444                                 int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
445                                 if(point1->control_x2 == 0 &&
446                                         point1->control_y2 == 0 &&
447                                         point2->control_x1 == 0 &&
448                                         point2->control_y1 == 0)
449                                         segments = 1;
450                                 float x0 = point1->x;
451                                 float y0 = point1->y;
452                                 float x1 = point1->x + point1->control_x2;
453                                 float y1 = point1->y + point1->control_y2;
454                                 float x2 = point2->x + point2->control_x1;
455                                 float y2 = point2->y + point2->control_y1;
456                                 float x3 = point2->x;
457                                 float y3 = point2->y;
458
459                                 for(int j = 0; j <= segments; j++)
460                                 {
461                                         float t = (float)j / segments;
462                                         float tpow2 = t * t;
463                                         float tpow3 = t * t * t;
464                                         float invt = 1 - t;
465                                         float invtpow2 = invt * invt;
466                                         float invtpow3 = invt * invt * invt;
467
468                                         x = (        invtpow3 * x0
469                                                 + 3 * t     * invtpow2 * x1
470                                                 + 3 * tpow2 * invt     * x2 
471                                                 +     tpow3            * x3);
472                                         y = (        invtpow3 * y0 
473                                                 + 3 * t     * invtpow2 * y1
474                                                 + 3 * tpow2 * invt     * y2 
475                                                 +     tpow3            * y3);
476
477                                         y -= ptr->start_y;
478                                         x *= OVERSAMPLE;
479                                         y *= OVERSAMPLE;
480
481                                         if(j > 0)
482                                         {
483                                                 draw_line_clamped(temp, old_x, old_y, (int)x, (int)y, max);
484                                         }
485
486                                         old_x = (int)x;
487                                         old_y = (int)y;
488                                 }
489                         }
490
491 SET_TRACE
492 //printf("MaskUnit::process_package 1\n");
493
494
495
496
497
498 // Fill in the polygon in the horizontal direction
499                         for(int i = 0; i < oversampled_package_h; i++)
500                         {
501                                 unsigned char *row = (unsigned char*)temp->get_rows()[i];
502                                 int value = 0x0;
503                                 int total = 0;
504
505                                 for(int j = 0; j < oversampled_package_w; j++)
506                                         if(row[j] == max) total++;
507
508                                 if(total > 1)
509                                 {
510                                         if(total & 0x1) total--;
511                                         for(int j = 0; j < oversampled_package_w; j++)
512                                         {
513                                                 if(row[j] == max && total > 0)
514                                                 {
515                                                         if(value)
516                                                                 value = 0x0;
517                                                         else
518                                                                 value = max;
519                                                         total--;
520                                                 }
521                                                 else
522                                                 {
523                                                         if(value) row[j] = value;
524                                                 }
525                                         }
526                                 }
527                         }
528                 }
529
530
531 SET_TRACE
532
533
534
535
536
537 #define DOWNSAMPLE(type, temp_type, value) \
538 for(int i = 0; i < ptr->end_y - ptr->start_y; i++) \
539 { \
540         type *output_row = (type*)mask->get_rows()[i + ptr->start_y]; \
541         unsigned char **input_rows = (unsigned char**)temp->get_rows() + i * OVERSAMPLE; \
542  \
543  \
544         for(int j = 0; j < mask_w; j++) \
545         { \
546                 temp_type total = 0; \
547  \
548 /* Accumulate pixel */ \
549                 for(int k = 0; k < OVERSAMPLE; k++) \
550                 { \
551                         unsigned char *input_vector = input_rows[k] + j * OVERSAMPLE; \
552                         for(int l = 0; l < OVERSAMPLE; l++) \
553                         { \
554                                 total += (input_vector[l] ? value : 0); \
555                         } \
556                 } \
557  \
558 /* Divide pixel */ \
559                 total /= OVERSAMPLE * OVERSAMPLE; \
560  \
561                 output_row[j] = total; \
562         } \
563 }
564
565 SET_TRACE
566
567 // Downsample polygon
568                 switch(mask->get_color_model())
569                 {
570                         case BC_A8:
571                         {
572                                 unsigned char value;
573                                 value = (int)((float)engine->value / 100 * 0xff);
574                                 DOWNSAMPLE(unsigned char, int64_t, value);
575                                 break;
576                         }
577
578                         case BC_A16:
579                         {
580                                 uint16_t value;
581                                 value = (int)((float)engine->value / 100 * 0xffff);
582                                 DOWNSAMPLE(uint16_t, int64_t, value);
583                                 break;
584                         }
585
586                         case BC_A_FLOAT:
587                         {
588                                 float value;
589                                 value = (float)engine->value / 100;
590                                 DOWNSAMPLE(float, double, value);
591                                 break;
592                         }
593                 }
594         }
595
596 SET_TRACE
597
598 SET_TRACE
599
600         if(engine->step == DO_X_FEATHER)
601         {
602
603                 if(engine->recalculate)
604                 {
605 // Feather polygon
606                         if(engine->feather > 0) do_feather(engine->mask, 
607                                 engine->temp_mask, 
608                                 engine->feather, 
609                                 ptr->start_y, 
610                                 ptr->end_y,
611                                 0,
612                                 0);
613                 }
614 //printf("MaskUnit::process_package 3 %f\n", engine->feather);
615         }
616
617         if(engine->step == DO_Y_FEATHER)
618         {
619                 if(engine->recalculate)
620                 {
621 // Feather polygon
622                         if(engine->feather > 0) do_feather(engine->mask, 
623                                 engine->temp_mask, 
624                                 engine->feather, 
625                                 0, 
626                                 0,
627                                 ptr->start_x,
628                                 ptr->end_x);
629                 }
630         }
631
632         if(engine->step == DO_APPLY)
633         {
634 // Apply mask
635                 int mask_w = engine->mask->get_w();
636
637
638 #define APPLY_MASK_SUBTRACT_ALPHA(type, max, components, do_yuv) \
639 { \
640         type *output_row = (type*)engine->output->get_rows()[i]; \
641         type *mask_row = (type*)engine->mask->get_rows()[i]; \
642         int chroma_offset = (int)(max + 1) / 2; \
643  \
644         for(int j  = 0; j < mask_w; j++) \
645         { \
646                 if(components == 4) \
647                 { \
648                         output_row[j * 4 + 3] = output_row[j * 4 + 3] * (max - mask_row[j]) / max; \
649                 } \
650                 else \
651                 { \
652                         output_row[j * 3] = output_row[j * 3] * (max - mask_row[j]) / max; \
653  \
654                         output_row[j * 3 + 1] = output_row[j * 3 + 1] * (max - mask_row[j]) / max; \
655                         output_row[j * 3 + 2] = output_row[j * 3 + 2] * (max - mask_row[j]) / max; \
656  \
657                         if(do_yuv) \
658                         { \
659                                 output_row[j * 3 + 1] += chroma_offset * mask_row[j] / max; \
660                                 output_row[j * 3 + 2] += chroma_offset * mask_row[j] / max; \
661                         } \
662                 } \
663         } \
664 }
665
666 #define APPLY_MASK_MULTIPLY_ALPHA(type, max, components, do_yuv) \
667 { \
668         type *output_row = (type*)engine->output->get_rows()[i]; \
669         type *mask_row = (type*)engine->mask->get_rows()[i]; \
670         int chroma_offset = (int)(max + 1) / 2; \
671  \
672         for(int j  = 0; j < mask_w; j++) \
673         { \
674                 if(components == 4) \
675                 { \
676                         output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / max; \
677                 } \
678                 else \
679                 { \
680                         output_row[j * 3] = output_row[j * 3] * mask_row[j] / max; \
681  \
682                         output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / max; \
683                         output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / max; \
684  \
685                         if(do_yuv) \
686                         { \
687                                 output_row[j * 3 + 1] += chroma_offset * (max - mask_row[j]) / max; \
688                                 output_row[j * 3 + 2] += chroma_offset * (max - mask_row[j]) / max; \
689                         } \
690                 } \
691         } \
692 }
693
694
695
696
697 //printf("MaskUnit::process_package 1 %d\n", engine->mode);
698                 for(int i = ptr->start_y; i < ptr->end_y; i++)
699                 {
700                         switch(engine->mode)
701                         {
702                                 case MASK_MULTIPLY_ALPHA:
703                                         switch(engine->output->get_color_model())
704                                         {
705                                                 case BC_RGB888:
706                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 0);
707                                                         break;
708                                                 case BC_RGB_FLOAT:
709                                                         APPLY_MASK_MULTIPLY_ALPHA(float, 1.0, 3, 0);
710                                                         break;
711                                                 case BC_YUV888:
712                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 1);
713                                                         break;
714                                                 case BC_RGBA_FLOAT:
715                                                         APPLY_MASK_MULTIPLY_ALPHA(float, 1.0, 4, 0);
716                                                         break;
717                                                 case BC_YUVA8888:
718                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 1);
719                                                         break;
720                                                 case BC_RGBA8888:
721                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 0);
722                                                         break;
723                                                 case BC_RGB161616:
724                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 0);
725                                                         break;
726                                                 case BC_YUV161616:
727                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 1);
728                                                         break;
729                                                 case BC_YUVA16161616:
730                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 1);
731                                                         break;
732                                                 case BC_RGBA16161616:
733                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 0);
734                                                         break;
735                                         }
736                                         break;
737
738                                 case MASK_SUBTRACT_ALPHA:
739                                         switch(engine->output->get_color_model())
740                                         {
741                                                 case BC_RGB888:
742                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 0);
743                                                         break;
744                                                 case BC_RGB_FLOAT:
745                                                         APPLY_MASK_SUBTRACT_ALPHA(float, 1.0, 3, 0);
746                                                         break;
747                                                 case BC_RGBA_FLOAT:
748                                                         APPLY_MASK_SUBTRACT_ALPHA(float, 1.0, 4, 0);
749                                                         break;
750                                                 case BC_RGBA8888:
751                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 0);
752                                                         break;
753                                                 case BC_YUV888:
754                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 1);
755                                                         break;
756                                                 case BC_YUVA8888:
757                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 1);
758                                                         break;
759                                                 case BC_RGB161616:
760                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 0);
761                                                         break;
762                                                 case BC_RGBA16161616:
763                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 0);
764                                                         break;
765                                                 case BC_YUV161616:
766                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 1);
767                                                         break;
768                                                 case BC_YUVA16161616:
769                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 1);
770                                                         break;
771                                         }
772                                         break;
773                         }
774                 }
775         }
776 }
777
778
779
780
781
782 MaskEngine::MaskEngine(int cpus)
783  : LoadServer(cpus, cpus * OVERSAMPLE * 2)
784 // : LoadServer(1, OVERSAMPLE * 2)
785 {
786         mask = 0;
787 }
788
789 MaskEngine::~MaskEngine()
790 {
791         if(mask) 
792         {
793                 delete mask;
794                 delete temp_mask;
795         }
796
797         for(int i = 0; i < point_sets.total; i++)
798         {
799                 ArrayList<MaskPoint*> *points = point_sets.values[i];
800                 points->remove_all_objects();
801         }
802         point_sets.remove_all_objects();
803 }
804
805 int MaskEngine::points_equivalent(ArrayList<MaskPoint*> *new_points, 
806         ArrayList<MaskPoint*> *points)
807 {
808 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
809         if(new_points->total != points->total) return 0;
810         
811         for(int i = 0; i < new_points->total; i++)
812         {
813                 if(!(*new_points->values[i] == *points->values[i])) return 0;
814         }
815         
816         return 1;
817 }
818
819 void MaskEngine::do_mask(VFrame *output, 
820         int64_t start_position_project,
821         MaskAutos *keyframe_set, 
822         MaskAuto *keyframe,
823         MaskAuto *default_auto)
824 {
825         int new_color_model = 0;
826         recalculate = 0;
827
828         switch(output->get_color_model())
829         {
830                 case BC_RGB_FLOAT:
831                 case BC_RGBA_FLOAT:
832                         new_color_model = BC_A_FLOAT;
833                         break;
834
835                 case BC_RGB888:
836                 case BC_RGBA8888:
837                 case BC_YUV888:
838                 case BC_YUVA8888:
839                         new_color_model = BC_A8;
840                         break;
841
842                 case BC_RGB161616:
843                 case BC_RGBA16161616:
844                 case BC_YUV161616:
845                 case BC_YUVA16161616:
846                         new_color_model = BC_A16;
847                         break;
848         }
849
850 // Determine if recalculation is needed
851 SET_TRACE
852
853         if(mask && 
854                 (mask->get_w() != output->get_w() ||
855                 mask->get_h() != output->get_h() ||
856                 mask->get_color_model() != new_color_model))
857         {
858                 delete mask;
859                 delete temp_mask;
860                 mask = 0;
861                 recalculate = 1;
862         }
863
864         if(!recalculate)
865         {
866                 if(point_sets.total != keyframe_set->total_submasks(start_position_project, 
867                         PLAY_FORWARD))
868                         recalculate = 1;
869         }
870
871         if(!recalculate)
872         {
873                 for(int i = 0; 
874                         i < keyframe_set->total_submasks(start_position_project, 
875                                 PLAY_FORWARD) && !recalculate; 
876                         i++)
877                 {
878                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
879                         keyframe_set->get_points(new_points, 
880                                 i, 
881                                 start_position_project, 
882                                 PLAY_FORWARD);
883                         if(!points_equivalent(new_points, point_sets.values[i])) recalculate = 1;
884                         new_points->remove_all_objects();
885                         delete new_points;
886                 }
887         }
888
889         int new_value = keyframe_set->get_value(start_position_project, 
890                 PLAY_FORWARD);
891         float new_feather = keyframe_set->get_feather(start_position_project, 
892                 PLAY_FORWARD);
893
894         if(recalculate ||
895                 !EQUIV(new_feather, feather) ||
896                 !EQUIV(new_value, value))
897         {
898                 recalculate = 1;
899                 if(!mask) 
900                 {
901                         mask = new VFrame(0, 
902                                         -1,
903                                         output->get_w(), 
904                                         output->get_h(),
905                                         new_color_model,
906                                         -1);
907                         temp_mask = new VFrame(0, 
908                                         -1,
909                                         output->get_w(), 
910                                         output->get_h(),
911                                         new_color_model,
912                                         -1);
913                 }
914                 if(new_feather > 0)
915                         temp_mask->clear_frame();
916                 else
917                         mask->clear_frame();
918
919                 for(int i = 0; i < point_sets.total; i++)
920                 {
921                         ArrayList<MaskPoint*> *points = point_sets.values[i];
922                         points->remove_all_objects();
923                 }
924                 point_sets.remove_all_objects();
925
926                 for(int i = 0; 
927                         i < keyframe_set->total_submasks(start_position_project, 
928                                 PLAY_FORWARD); 
929                         i++)
930                 {
931                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
932                         keyframe_set->get_points(new_points, 
933                                 i, 
934                                 start_position_project, 
935                                 PLAY_FORWARD);
936                         point_sets.append(new_points);
937                 }
938         }
939
940
941
942         this->output = output;
943         this->mode = default_auto->mode;
944         this->feather = new_feather;
945         this->value = new_value;
946
947
948 // Run units
949 SET_TRACE
950         step = DO_MASK;
951         process_packages();
952         step = DO_Y_FEATHER;
953         process_packages();
954         step = DO_X_FEATHER;
955         process_packages();
956         step = DO_APPLY;
957         process_packages();
958 SET_TRACE
959
960
961 }
962
963 void MaskEngine::init_packages()
964 {
965 SET_TRACE
966 //printf("MaskEngine::init_packages 1\n");
967         int division = (int)((float)output->get_h() / (get_total_packages() / 2) + 0.5);
968         if(division < 1) division = 1;
969
970 SET_TRACE
971         for(int i = 0; i < get_total_packages(); i++)
972         {
973                 MaskPackage *ptr = (MaskPackage*)get_package(i);
974
975                 ptr->start_y = output->get_h() * i / get_total_packages();
976                 ptr->end_y = output->get_h() * (i + 1) / get_total_packages();
977
978                 ptr->start_x = output->get_w() * i / get_total_packages();
979                 ptr->end_x = output->get_w() * (i + 1) / get_total_packages();
980         }
981 SET_TRACE
982 //printf("MaskEngine::init_packages 2\n");
983 }
984
985 LoadClient* MaskEngine::new_client()
986 {
987         return new MaskUnit(this);
988 }
989
990 LoadPackage* MaskEngine::new_package()
991 {
992         return new MaskPackage;
993 }
994