Fourth set of 50 GPL attribution for CV-Contributors added +
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / deinterlace-cv / deinterlace-cv.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "clip.h"
24 #include "bchash.h"
25 #include "deinterlace-cv.h"
26 #include "deinterwindow-cv.h"
27 #include "filexml.h"
28 #include "keyframe.h"
29 #include "language.h"
30 #include "vframe.h"
31
32
33
34
35
36
37
38
39
40 #include <stdint.h>
41 #include <string.h>
42 #include <math.h>
43
44 REGISTER_PLUGIN(DeInterlaceMain)
45
46
47
48
49 DeInterlaceConfig::DeInterlaceConfig()
50 {
51         mode = DEINTERLACE_AVG;
52         dominance = 0;
53         adaptive = 1;
54         threshold = 40;
55 }
56
57 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
58 {
59         return mode == that.mode &&
60                 dominance == that.dominance &&
61                 adaptive == that.adaptive &&
62                 threshold == that.threshold;
63 }
64
65 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
66 {
67         mode = that.mode;
68         dominance = that.dominance;
69         adaptive = that.adaptive;
70         threshold = that.threshold;
71 }
72
73 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
74         DeInterlaceConfig &next,
75         int64_t prev_frame,
76         int64_t next_frame,
77         int64_t current_frame)
78 {
79         copy_from(prev);
80 }
81
82
83
84
85 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
86  : PluginVClient(server)
87 {
88 //      temp = 0;
89         temp_prevframe=0;
90 }
91
92 DeInterlaceMain::~DeInterlaceMain()
93 {
94 //      if(temp) delete temp;
95         if(temp_prevframe) delete temp_prevframe;
96 }
97
98 const char* DeInterlaceMain::plugin_title() { return N_("Deinterlace-CV"); }
99 int DeInterlaceMain::is_realtime() { return 1; }
100
101
102
103 #define DEINTERLACE_TOP_MACRO(type, components, dominance) \
104 { \
105         int w = input->get_w(); \
106         int h = input->get_h(); \
107  \
108         for(int i = 0; i < h - 1; i += 2) \
109         { \
110                 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
111                 type *output_row1 = (type*)output->get_rows()[i]; \
112                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
113                 memcpy(output_row1, input_row, w * components * sizeof(type)); \
114                 memcpy(output_row2, input_row, w * components * sizeof(type)); \
115         } \
116 }
117
118 #define DEINTERLACE_AVG_TOP_MACRO(type, temp_type, components, dominance) \
119 { \
120         int w = input->get_w(); \
121         int h = input->get_h(); \
122         changed_rows = 0; \
123  \
124         type **in_rows = (type**)input->get_rows(); \
125         type **out_rows = (type**)temp->get_rows(); \
126         int max_h = h - 1; \
127         temp_type abs_diff = 0, total = 0; \
128  \
129         for(int i = 0; i < max_h; i += 2) \
130         { \
131                 int in_number1 = dominance ? i - 1 : i + 0; \
132                 int in_number2 = dominance ? i + 1 : i + 2; \
133                 int out_number1 = dominance ? i - 1 : i; \
134                 int out_number2 = dominance ? i : i + 1; \
135                 in_number1 = MAX(in_number1, 0); \
136                 in_number2 = MIN(in_number2, max_h); \
137                 out_number1 = MAX(out_number1, 0); \
138                 out_number2 = MIN(out_number2, max_h); \
139  \
140                 type *input_row1 = in_rows[in_number1]; \
141                 type *input_row2 = in_rows[in_number2]; \
142                 type *input_row3 = in_rows[out_number2]; \
143                 type *temp_row1 = out_rows[out_number1]; \
144                 type *temp_row2 = out_rows[out_number2]; \
145                 temp_type sum = 0; \
146                 temp_type accum_r, accum_b, accum_g, accum_a; \
147  \
148                 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
149                 for(int j = 0; j < w; j++) \
150                 { \
151                         accum_r = (*input_row1++) + (*input_row2++); \
152                         accum_g = (*input_row1++) + (*input_row2++); \
153                         accum_b = (*input_row1++) + (*input_row2++); \
154                         if(components == 4) \
155                                 accum_a = (*input_row1++) + (*input_row2++); \
156                         accum_r /= 2; \
157                         accum_g /= 2; \
158                         accum_b /= 2; \
159                         accum_a /= 2; \
160  \
161                         total += *input_row3; \
162                         sum = ((temp_type)*input_row3++) - accum_r; \
163                         abs_diff += (sum < 0 ? -sum : sum); \
164                         *temp_row2++ = accum_r; \
165  \
166                         total += *input_row3; \
167                         sum = ((temp_type)*input_row3++) - accum_g; \
168                         abs_diff += (sum < 0 ? -sum : sum); \
169                         *temp_row2++ = accum_g; \
170  \
171                         total += *input_row3; \
172                         sum = ((temp_type)*input_row3++) - accum_b; \
173                         abs_diff += (sum < 0 ? -sum : sum); \
174                         *temp_row2++ = accum_b; \
175  \
176                         if(components == 4) \
177                         { \
178                                 total += *input_row3; \
179                                 sum = ((temp_type)*input_row3++) - accum_a; \
180                                 abs_diff += (sum < 0 ? -sum : sum); \
181                                 *temp_row2++ = accum_a; \
182                         } \
183                 } \
184         } \
185  \
186         temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; \
187 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
188         if(abs_diff > threshold || !config.adaptive) \
189         { \
190                 output->copy_from(temp); \
191                 changed_rows = 240; \
192         } \
193         else \
194         { \
195                 output->copy_from(input); \
196                 changed_rows = 0; \
197         } \
198  \
199 }
200
201 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
202 { \
203         int w = input->get_w(); \
204         int h = input->get_h(); \
205  \
206         for(int i = 0; i < h - 1; i += 2) \
207         { \
208                 type *input_row1 = (type*)input->get_rows()[i]; \
209                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
210                 type *output_row1 = (type*)output->get_rows()[i]; \
211                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
212                 type result; \
213  \
214                 for(int j = 0; j < w * components; j++) \
215                 { \
216                         result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
217                         output_row1[j] = result; \
218                         output_row2[j] = result; \
219                 } \
220         } \
221 }
222
223 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
224 { \
225         int w = input->get_w(); \
226         int h = input->get_h(); \
227  \
228         for(int i = dominance; i < h - 1; i += 2) \
229         { \
230                 type *input_row1 = (type*)input->get_rows()[i]; \
231                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
232                 type *output_row1 = (type*)output->get_rows()[i]; \
233                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
234                 type temp1, temp2; \
235  \
236                 for(int j = 0; j < w * components; j++) \
237                 { \
238                         temp1 = input_row1[j]; \
239                         temp2 = input_row2[j]; \
240                         output_row1[j] = temp2; \
241                         output_row2[j] = temp1; \
242                 } \
243         } \
244 }
245
246
247 #define DEINTERLACE_TEMPORALSWAP_MACRO(type, components, dominance) \
248 { \
249         int w = input->get_w(); \
250         int h = input->get_h(); \
251  \
252         for(int i = 0; i < h - 1; i += 2) \
253         { \
254                 type *input_row1;\
255                 type *input_row2; \
256                 type *output_row1 = (type*)output->get_rows()[i]; \
257                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
258                 type temp1, temp2; \
259                 \
260                 if (dominance) { \
261                         input_row1 = (type*)input->get_rows()[i]; \
262                         input_row2 = (type*)prevframe->get_rows()[i+1]; \
263                 } \
264                 else  {\
265                         input_row1 = (type*)prevframe->get_rows()[i]; \
266                         input_row2 = (type*)input->get_rows()[i+1]; \
267                 } \
268  \
269                 for(int j = 0; j < w * components; j++) \
270                 { \
271                         temp1 = input_row1[j]; \
272                         temp2 = input_row2[j]; \
273                         output_row1[j] = temp1; \
274                         output_row2[j] = temp2; \
275                 } \
276         } \
277 }
278
279
280 /* Bob & Weave deinterlacer:
281
282 For each pixel,
283         if it's similar to the previous frame
284         then keep it
285         else average with line above and below
286
287 Similar is defined as in abs(difference)/(sum) < threshold
288 */
289 // cplr warns, #define FABS(a) (((a)<0)?(0-(a)):(a))
290 static inline int FABS(int8_t v) { return v<0 ? -v : v; }
291 static inline int FABS(uint8_t v) { return v; }
292 static inline int FABS(int16_t v) { return v<0 ? -v : v; }
293 static inline int FABS(uint16_t v) { return v; }
294 static inline int FABS(int32_t v) { return v<0 ? -v : v; }
295 static inline int64_t FABS(uint32_t v) { return v; }
296 static inline int64_t FABS(int64_t v) { return v<0 ? -v : v; }
297 static inline int64_t FABS(uint64_t v) { return v; }
298 static inline float FABS(float v) { return v<0 ? -v : v; }
299 static inline double FABS(double v) { return v<0 ? -v : v; }
300 #define FMAX(a,b) (((a)>(b))?(a):(b))
301 #define FMIN(a,b) (((a)<(b))?(a):(b))
302
303 #define SQ(a) ((a)*(a))
304 // threshold < 100 -> a-b/a+b <
305
306
307 #define DEINTERLACE_BOBWEAVE_MACRO(type, temp_type, components, dominance, threshold, noise_threshold) \
308 { \
309         /* Ooooohh, I like fudge factors */ \
310         double exp_threshold=exp(((double)threshold - 50 )/2);\
311         int w = input->get_w(); \
312         int h = input->get_h(); \
313         type *row_above=(type*)input->get_rows()[0]; \
314         for(int i = dominance ?0:1; i < h - 1; i += 2) \
315         { \
316                 type *input_row;\
317                 type *input_row2; \
318                 type *old_row; \
319                 type *output_row1 = (type*)output->get_rows()[i]; \
320                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
321                 temp_type pixel, below, old, above; \
322                 \
323                 input_row = (type*)input->get_rows()[i]; \
324                 input_row2 = (type*)input->get_rows()[i+1]; \
325                 old_row = (type*)prevframe->get_rows()[i]; \
326 \
327                 for(int j = 0; j < w * components; j++) \
328                 { \
329                         pixel = input_row[j]; \
330                         below = input_row2[j]; \
331                         old = old_row[j]; \
332                         above = row_above[j]; \
333 \
334                         if  ( ( FABS(pixel-old) <= noise_threshold )  \
335                         || ((pixel+old != 0) && (((FABS((double) pixel-old))/((double) pixel+old)) >= exp_threshold )) \
336                         || ((above+below != 0) && (((FABS((double) pixel-old))/((double) above+below)) >= exp_threshold )) \
337                         ) {\
338                                 pixel=(above+below)/2 ;\
339                         }\
340                         output_row1[j] = pixel; \
341                         output_row2[j] = below; \
342                 } \
343                 row_above=input_row2; \
344         } \
345 }
346
347
348 void DeInterlaceMain::deinterlace_top(VFrame *input, VFrame *output, int dominance)
349 {
350         switch(input->get_color_model())
351         {
352                 case BC_RGB888:
353                 case BC_YUV888:
354                         DEINTERLACE_TOP_MACRO(unsigned char, 3, dominance);
355                         break;
356                 case BC_RGB_FLOAT:
357                         DEINTERLACE_TOP_MACRO(float, 3, dominance);
358                         break;
359                 case BC_RGBA8888:
360                 case BC_YUVA8888:
361                         DEINTERLACE_TOP_MACRO(unsigned char, 4, dominance);
362                         break;
363                 case BC_RGBA_FLOAT:
364                         DEINTERLACE_TOP_MACRO(float, 4, dominance);
365                         break;
366                 case BC_RGB161616:
367                 case BC_YUV161616:
368                         DEINTERLACE_TOP_MACRO(uint16_t, 3, dominance);
369                         break;
370                 case BC_RGBA16161616:
371                 case BC_YUVA16161616:
372                         DEINTERLACE_TOP_MACRO(uint16_t, 4, dominance);
373                         break;
374         }
375 }
376
377 void DeInterlaceMain::deinterlace_avg_top(VFrame *input, VFrame *output, int dominance)
378 {
379         switch(input->get_color_model())
380         {
381                 case BC_RGB888:
382                 case BC_YUV888:
383                         DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 3, dominance);
384                         break;
385                 case BC_RGB_FLOAT:
386                         DEINTERLACE_AVG_TOP_MACRO(float, double, 3, dominance);
387                         break;
388                 case BC_RGBA8888:
389                 case BC_YUVA8888:
390                         DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 4, dominance);
391                         break;
392                 case BC_RGBA_FLOAT:
393                         DEINTERLACE_AVG_TOP_MACRO(float, double, 4, dominance);
394                         break;
395                 case BC_RGB161616:
396                 case BC_YUV161616:
397                         DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 3, dominance);
398                         break;
399                 case BC_RGBA16161616:
400                 case BC_YUVA16161616:
401                         DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 4, dominance);
402                         break;
403         }
404 }
405
406 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
407 {
408         switch(input->get_color_model())
409         {
410                 case BC_RGB888:
411                 case BC_YUV888:
412                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
413                         break;
414                 case BC_RGB_FLOAT:
415                         DEINTERLACE_AVG_MACRO(float, double, 3);
416                         break;
417                 case BC_RGBA8888:
418                 case BC_YUVA8888:
419                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
420                         break;
421                 case BC_RGBA_FLOAT:
422                         DEINTERLACE_AVG_MACRO(float, double, 4);
423                         break;
424                 case BC_RGB161616:
425                 case BC_YUV161616:
426                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
427                         break;
428                 case BC_RGBA16161616:
429                 case BC_YUVA16161616:
430                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
431                         break;
432         }
433 }
434
435 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
436 {
437         switch(input->get_color_model())
438         {
439                 case BC_RGB888:
440                 case BC_YUV888:
441                         DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
442                         break;
443                 case BC_RGB_FLOAT:
444                         DEINTERLACE_SWAP_MACRO(float, 3, dominance);
445                         break;
446                 case BC_RGBA8888:
447                 case BC_YUVA8888:
448                         DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
449                         break;
450                 case BC_RGBA_FLOAT:
451                         DEINTERLACE_SWAP_MACRO(float, 4, dominance);
452                         break;
453                 case BC_RGB161616:
454                 case BC_YUV161616:
455                         DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
456                         break;
457                 case BC_RGBA16161616:
458                 case BC_YUVA16161616:
459                         DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
460                         break;
461         }
462 }
463
464 void DeInterlaceMain::deinterlace_temporalswap(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
465 {
466         switch(input->get_color_model())
467         {
468                 case BC_RGB888:
469                 case BC_YUV888:
470                         DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 3, dominance);
471                         break;
472                 case BC_RGB_FLOAT:
473                         DEINTERLACE_TEMPORALSWAP_MACRO(float, 3, dominance);
474                         break;
475                 case BC_RGBA8888:
476                 case BC_YUVA8888:
477                         DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 4, dominance);
478                         break;
479                 case BC_RGBA_FLOAT:
480                         DEINTERLACE_TEMPORALSWAP_MACRO(float, 4, dominance);
481                         break;
482                 case BC_RGB161616:
483                 case BC_YUV161616:
484                         DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 3, dominance);
485                         break;
486                 case BC_RGBA16161616:
487                 case BC_YUVA16161616:
488                         DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 4, dominance);
489                         break;
490         }
491 }
492
493 void DeInterlaceMain::deinterlace_bobweave(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
494 {
495         int threshold=config.threshold;
496         int noise_threshold=0;
497
498         switch(input->get_color_model())
499         {
500                 case BC_RGB888:
501                 case BC_YUV888:
502                         DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 3, dominance, threshold, noise_threshold);
503                         break;
504                 case BC_RGB_FLOAT:
505                         DEINTERLACE_BOBWEAVE_MACRO(float, double, 3, dominance, threshold, noise_threshold);
506                         break;
507                 case BC_RGBA8888:
508                 case BC_YUVA8888:
509                         DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 4, dominance, threshold, noise_threshold);
510                         break;
511                 case BC_RGBA_FLOAT:
512                         DEINTERLACE_BOBWEAVE_MACRO(float, double, 4, dominance, threshold, noise_threshold);
513                         break;
514                 case BC_RGB161616:
515                 case BC_YUV161616:
516                         DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 3, dominance, threshold, noise_threshold);
517                         break;
518                 case BC_RGBA16161616:
519                 case BC_YUVA16161616:
520                         DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 4, dominance, threshold, noise_threshold);
521                         break;
522         }
523 }
524
525
526 int DeInterlaceMain::process_buffer(VFrame *frame,
527         int64_t start_position,
528         double frame_rate)
529 {
530         changed_rows = frame->get_h();
531         load_configuration();
532
533
534         read_frame(frame, 0, start_position, frame_rate, 0);
535
536 // Temp was used for adaptive deinterlacing where it took deinterlacing
537 // an entire frame to decide if the deinterlaced output should be used.
538         temp = frame;
539
540 //      if(!temp)
541 //              temp = new VFrame(frame->get_w(), frame->get_h(),
542 //                      frame->get_color_model(), 0);
543         if(!temp_prevframe)
544                 temp_prevframe = new VFrame(frame->get_w(), frame->get_h(),
545                         frame->get_color_model(), 0);
546
547         switch(config.mode)
548         {
549                 case DEINTERLACE_NONE:
550 //                      output->copy_from(input);
551                         break;
552                 case DEINTERLACE_KEEP:
553                         deinterlace_top(frame, frame, config.dominance);
554                         break;
555                 case DEINTERLACE_AVG:
556                         deinterlace_avg(frame, frame);
557                         break;
558                 case DEINTERLACE_AVG_1F:
559                         deinterlace_avg_top(frame, frame, config.dominance);
560                         break;
561                 case DEINTERLACE_SWAP:
562                         deinterlace_swap(frame, frame, config.dominance);
563                         break;
564                 case DEINTERLACE_BOBWEAVE:
565                         if (get_source_position()==0)
566                                 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
567                         else
568                                 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
569                         deinterlace_bobweave(frame, temp_prevframe, frame, config.dominance);
570                         break;
571                 case DEINTERLACE_TEMPORALSWAP:
572                         if (get_source_position()==0)
573                                 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
574                         else
575                                 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
576                         deinterlace_temporalswap(frame, temp_prevframe, frame, config.dominance);
577                         break;
578         }
579         send_render_gui(&changed_rows);
580         return 0;
581 }
582
583
584 void DeInterlaceMain::render_gui(void *data)
585 {
586         if(thread)
587         {
588                 thread->window->lock_window();
589                 char string[BCTEXTLEN];
590                 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
591                 window->get_status_string(string, *(int*)data);
592                 window->status->update(string);
593                 window->flush();
594                 window->unlock_window();
595         }
596 }
597
598 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
599 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
600
601
602
603 void DeInterlaceMain::save_data(KeyFrame *keyframe)
604 {
605         FileXML output;
606         output.set_shared_output(keyframe->xbuf);
607         output.tag.set_title("DEINTERLACE");
608         output.tag.set_property("MODE", config.mode);
609         output.tag.set_property("DOMINANCE", config.dominance);
610         output.tag.set_property("ADAPTIVE", config.adaptive);
611         output.tag.set_property("THRESHOLD", config.threshold);
612         output.append_tag();
613         output.tag.set_title("/DEINTERLACE");
614         output.append_tag();
615         output.terminate_string();
616 }
617
618 void DeInterlaceMain::read_data(KeyFrame *keyframe)
619 {
620         FileXML input;
621         input.set_shared_input(keyframe->xbuf);
622
623         while(!input.read_tag())
624         {
625                 if(input.tag.title_is("DEINTERLACE"))
626                 {
627                         config.mode = input.tag.get_property("MODE", config.mode);
628                         config.dominance = input.tag.get_property("DOMINANCE", config.dominance);
629                         config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
630                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
631                 }
632         }
633
634 }
635
636 void DeInterlaceMain::update_gui()
637 {
638         if(thread)
639         {
640                 load_configuration();
641                 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
642                 window->lock_window();
643                 window->set_mode(config.mode, 1);
644                 if (window->dominance_top)
645                         window->dominance_top->update(config.dominance?0:BC_Toggle::TOGGLE_CHECKED);
646                 if (window->dominance_bottom)
647                         window->dominance_bottom->update(config.dominance?BC_Toggle::TOGGLE_CHECKED:0);
648                 if (window->adaptive)
649                         window->adaptive->update(config.adaptive);
650                 if (window->threshold)
651                         window->threshold->update(config.threshold);
652                 window->unlock_window();
653         }
654 }
655