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