additional TERMUX related mods from Andrew
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / histogram_bezier / bistogramconfig.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 "bistogramconfig.h"
24 #include "units.h"
25
26 #include <math.h>
27
28
29 HistogramPoint::HistogramPoint()
30  : ListItem<HistogramPoint>()
31 {
32         x = 0;  y = 0;
33         xoffset_left = -0.05;
34         xoffset_right = 0.05;
35         gradient = 1.0;
36
37 }
38
39 HistogramPoint::~HistogramPoint()
40 {
41 }
42
43 int HistogramPoint::equivalent(HistogramPoint *src)
44 {
45         return EQUIV(x, src->x) && EQUIV(y, src->y) &&
46                 EQUIV(xoffset_left, src->xoffset_left) &&
47                 EQUIV(xoffset_right, src->xoffset_right) &&
48                 EQUIV(gradient, src->gradient);
49 }
50
51 void HistogramPoint::copy_from(HistogramPoint *that)
52 {
53         x = that->x;  y = that->y;
54         xoffset_left = that->xoffset_left;
55         xoffset_right = that->xoffset_right;
56         gradient = that->gradient;
57
58 }
59
60
61 HistogramPoints::HistogramPoints()
62  : List<HistogramPoint>()
63 {
64         clear();
65 }
66
67 HistogramPoints::~HistogramPoints()
68 {
69 }
70
71 void HistogramPoints::clear()
72 {
73         while( last ) delete last;
74         insert(0.0,0.0);
75         first->gradient = 1.0;
76         first->xoffset_left = 0.0;
77         first->xoffset_right = 0.05;
78         insert(1.0,1.0);
79         last->gradient = 1.0;
80         last->xoffset_left = -0.05;
81         last->xoffset_right = 0.0;
82 }
83
84 HistogramPoint* HistogramPoints::insert(float x, float y)
85 {
86         HistogramPoint *current = first;
87
88 // Get existing point after new point
89         while( current ) {
90                 if( current->x > x ) break;
91                 current = NEXT;
92         }
93
94 // Insert new point before current point
95         HistogramPoint *new_point = new HistogramPoint;
96         if( current )
97                 insert_before(current, new_point);
98         else
99                 append(new_point);
100
101         new_point->x = x;
102         new_point->y = y;
103         return new_point;
104 }
105
106 void HistogramPoints::boundaries()
107 {
108         HistogramPoint *current = first;
109         while( current ) {
110                 CLAMP(current->x, 0.0, 1.0);
111                 CLAMP(current->y, 0.0, 1.0);
112                 current = NEXT;
113         }
114 }
115
116 int HistogramPoints::equivalent(HistogramPoints *src)
117 {
118         HistogramPoint *current_this = first;
119         HistogramPoint *current_src = src->first;
120         while( current_this && current_src ) {
121                 if(!current_this->equivalent(current_src)) return 0;
122                 current_this = current_this->next;
123                 current_src = current_src->next;
124         }
125
126         return current_this || current_src ? 0 : 1;
127 }
128
129 void HistogramPoints::copy_from(HistogramPoints *src)
130 {
131         while(last)
132                 delete last;
133         HistogramPoint *current = src->first;
134         while( current ) {
135                 HistogramPoint *new_point = new HistogramPoint;
136                 new_point->copy_from(current);
137                 append(new_point);
138                 current = NEXT;
139         }
140 }
141
142 int HistogramPoints::cmprx(HistogramPoint *ap, HistogramPoint *bp)
143 {
144         return ap->x < bp->x ? -1 : ap->x == bp->x ? 0 : 1;
145 }
146
147 void HistogramPoints::interpolate(HistogramPoints *prev, HistogramPoints *next,
148                 double prev_scale, double next_scale)
149 {
150         HistogramPoint *current_prev = prev->first;
151         HistogramPoint *current_next = next->first;
152
153         HistogramPoint *current = first;
154         while( current_prev || current_next ) {
155                 if( !current ) {
156                         current = new HistogramPoint;
157                         append(current);
158                 }
159                 if( !current_next ) {
160                         current->copy_from(current_prev);
161                         current_prev = current_prev->next;
162                 }
163                 else if( !current_prev ) {
164                         current->copy_from(current_next);
165                         current_next = current_next->next;
166                 }
167                 else {
168                         current->x = current_prev->x * prev_scale +
169                                         current_next->x * next_scale;
170                         current->y = current_prev->y * prev_scale +
171                                         current_next->y * next_scale;
172                         current->gradient = current_prev->gradient * prev_scale +
173                                         current_next->gradient * next_scale;
174                         current->xoffset_left = current_prev->xoffset_left * prev_scale +
175                                         current_next->xoffset_left * next_scale;
176                         current->xoffset_right = current_prev->xoffset_right * prev_scale +
177                                         current_next->xoffset_right * next_scale;
178                         current_prev = current_prev->next;
179                         current_next = current_next->next;
180                 }
181                 current = current->next;
182         }
183
184         while( current ) {
185                 HistogramPoint *next_point = current->next;
186                 delete current;  current = next_point;
187         }
188         sort(cmprx);
189 }
190
191
192 HistogramConfig::HistogramConfig()
193 {
194         reset(1);
195 }
196
197 void HistogramConfig::reset(int do_mode)
198 {
199         reset_points();
200         for( int i = 0; i < HISTOGRAM_MODES; i++ ) {
201                 output_min[i] = 0.0;
202                 output_max[i] = 1.0;
203         }
204
205         if( do_mode ) {
206                 automatic = 0;
207                 threshold = 1.0;
208                 split = 0;
209                 smoothMode = 0;
210         }
211 }
212
213 void HistogramConfig::reset_points()
214 {
215         for( int i=0; i<HISTOGRAM_MODES; ++i )
216                 points[i].clear();
217 }
218
219
220 void HistogramConfig::boundaries()
221 {
222         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
223                 points[i].boundaries();
224                 CLAMP(output_min[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
225                 CLAMP(output_max[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
226                 output_min[i] = Units::quantize(output_min[i], PRECISION);
227                 output_max[i] = Units::quantize(output_max[i], PRECISION);
228         }
229         CLAMP(threshold, 0, 1);
230 }
231
232 int HistogramConfig::equivalent(HistogramConfig &that)
233 {
234         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
235                 if( !points[i].equivalent(&that.points[i]) ||
236                     !EQUIV(output_min[i], that.output_min[i]) ||
237                     !EQUIV(output_max[i], that.output_max[i]) ) return 0;
238         }
239
240         if( automatic != that.automatic ||
241             split != that.split ||
242             smoothMode != that.smoothMode ||
243             !EQUIV(threshold, that.threshold) ) return 0;
244
245         return 1;
246 }
247
248 void HistogramConfig::copy_from(HistogramConfig &that)
249 {
250         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
251                 points[i].copy_from(&that.points[i]);
252                 output_min[i] = that.output_min[i];
253                 output_max[i] = that.output_max[i];
254         }
255
256         automatic = that.automatic;
257         threshold = that.threshold;
258         split = that.split;
259         smoothMode = that.smoothMode;
260 }
261
262 void HistogramConfig::interpolate(HistogramConfig &prev, HistogramConfig &next,
263         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
264 {
265         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
266         double prev_scale = 1.0 - next_scale;
267
268         for( int i=0; i<HISTOGRAM_MODES; ++i ) {
269                 points[i].interpolate(&prev.points[i], &next.points[i], prev_scale, next_scale);
270                 output_min[i] = prev.output_min[i] * prev_scale + next.output_min[i] * next_scale;
271                 output_max[i] = prev.output_max[i] * prev_scale + next.output_max[i] * next_scale;
272         }
273
274         threshold = prev.threshold * prev_scale + next.threshold * next_scale;
275         automatic = prev.automatic;
276         split = prev.split;
277         smoothMode = prev.smoothMode;
278 }
279
280
281 void HistogramConfig::dump()
282 {
283         printf("HistogramConfig::dump: automatic=%d, threshold=%f, split=%d, smoothMode=%d\n",
284                 automatic, threshold, split, smoothMode);
285         static const char *mode_name[] = { "red","grn","blu","val" };
286         for( int j=0; j<HISTOGRAM_MODES; ++j ) {
287                 printf("mode[%s]:\n", mode_name[j]);
288                 HistogramPoints *points = &this->points[j];
289                 HistogramPoint *current = points->first;
290                 while( current ) {
291                         printf("%f,%f (@%f l%f,r%f)\n", current->x, current->y,
292                                 current->gradient, current->xoffset_left, current->xoffset_right);
293                         fflush(stdout);
294                         current = NEXT;
295                 }
296         }
297 }
298