no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / alpha / alpha.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2019 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 #include <math.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include "alpha.h"
26 #include "theme.h"
27 #include "filexml.h"
28 #include "keyframe.h"
29 #include "language.h"
30 #include "vframe.h"
31
32 REGISTER_PLUGIN(AlphaMain)
33
34
35 AlphaConfig::AlphaConfig()
36 {
37         reset();
38 }
39
40 void AlphaConfig::reset()
41 {
42         a = 1.;
43 }
44
45 int AlphaConfig::equivalent(AlphaConfig &that)
46 {
47         return a == that.a;
48 }
49
50 void AlphaConfig::copy_from(AlphaConfig &that)
51 {
52         a = that.a;
53 }
54
55 void AlphaConfig::interpolate(AlphaConfig &prev, AlphaConfig &next,
56                 long prev_frame, long next_frame, long current_frame)
57 {
58         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
59         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
60
61         a = (prev.a * prev_scale + next.a * next_scale);
62 }
63
64
65 AlphaText::AlphaText(AlphaWindow *window, AlphaMain *plugin,
66                 int x, int y)
67  : BC_TumbleTextBox(window, (float)plugin->config.a,
68         (float)OPACITY_MIN, (float)OPACITY_MAX, x, y, xS(60), 2)
69 {
70         this->window = window;
71         this->plugin = plugin;
72         set_increment(0.1);
73 }
74 AlphaText::~AlphaText()
75 {
76 }
77
78 int AlphaText::handle_event()
79 {
80         float min = OPACITY_MIN, max = OPACITY_MAX;
81         float output = atof(get_text());
82
83         if(output > max) output = max;
84         else if(output < min) output = min;
85         plugin->config.a = output;
86         window->alpha_slider->update(plugin->config.a);
87         window->alpha_text->update(plugin->config.a);
88         plugin->send_configure_change();
89         return 1;
90 }
91
92 AlphaSlider::AlphaSlider(AlphaWindow *window, AlphaMain *plugin,
93                 int x, int y, int w)
94  : BC_FSlider(x, y, 0, w, w, OPACITY_MIN, OPACITY_MAX, plugin->config.a)
95 {
96         this->window = window;
97         this->plugin = plugin;
98         enable_show_value(0); // Hide caption
99         set_precision(0.001);
100 }
101 AlphaSlider::~AlphaSlider()
102 {
103 }
104
105 int AlphaSlider::handle_event()
106 {
107         plugin->config.a = get_value();
108         window->alpha_text->update(plugin->config.a);
109         plugin->send_configure_change();
110         return 1;
111 }
112
113 AlphaClr::AlphaClr(AlphaWindow *window, AlphaMain *plugin, int x, int y)
114  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
115 {
116         this->window = window;
117         this->plugin = plugin;
118 }
119 AlphaClr::~AlphaClr()
120 {
121 }
122 int AlphaClr::handle_event()
123 {
124         plugin->config.reset();
125         window->update();
126         plugin->send_configure_change();
127         return 1;
128 }
129
130
131 #define ALPHA_W xS(420)
132 #define ALPHA_H yS(60)
133
134 AlphaWindow::AlphaWindow(AlphaMain *plugin)
135  : PluginClientWindow(plugin, ALPHA_W, ALPHA_H, ALPHA_W, ALPHA_H, 0)
136 {
137         this->plugin = plugin;
138 }
139
140 AlphaWindow::~AlphaWindow()
141 {
142 }
143
144 void AlphaWindow::create_objects()
145 {
146         int xs10 = xS(10), xs200 = xS(200);
147         int ys10 = yS(10);
148         int x = xs10, y = ys10;
149         int x2 = xS(80), x3 = xS(180);
150         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
151
152         BC_Title *title;
153
154         y += ys10;
155         add_subwindow(title = new BC_Title(x, y, _("Alpha:")));
156         alpha_text = new AlphaText(this, plugin, (x + x2), y);
157         alpha_text->create_objects();
158         add_subwindow(alpha_slider = new AlphaSlider(this, plugin, x3, y, xs200));
159         clr_x = x3 + alpha_slider->get_w() + x;
160         add_subwindow(alpha_clr = new AlphaClr(this, plugin, clr_x, y));
161         show_window();
162 }
163
164 void AlphaWindow::update()
165 {
166         float alpha = plugin->config.a;
167         alpha_text->update(alpha);
168         alpha_slider->update(alpha);
169 }
170
171
172 AlphaMain::AlphaMain(PluginServer *server)
173  : PluginVClient(server)
174 {
175 }
176
177 AlphaMain::~AlphaMain()
178 {
179 }
180
181 const char* AlphaMain::plugin_title() { return N_("Alpha"); }
182 int AlphaMain::is_realtime() { return 1; }
183
184 NEW_WINDOW_MACRO(AlphaMain, AlphaWindow)
185
186 LOAD_CONFIGURATION_MACRO(AlphaMain, AlphaConfig)
187
188 int AlphaMain::is_synthesis()
189 {
190         return 1;
191 }
192
193
194 int AlphaMain::process_buffer(VFrame *frame,
195         int64_t start_position,
196         double frame_rate)
197 {
198         load_configuration();
199
200         read_frame(frame, 0, start_position, frame_rate, get_use_opengl());
201         int w = frame->get_w(), h = frame->get_h();
202
203 #define MAIN_LOOP(type, components, is_yuv, max) do { \
204         if( components == 4 ) { \
205                 for( int y=0; y<h; ++y ) { \
206                         type *row = (type*)frame->get_rows()[y]; \
207                         for( int x=0; x<w; ++x ) { \
208                                 row[3] = a * max; \
209                                 row += components; \
210                         } \
211                 } \
212         } \
213         else if( is_yuv ) { \
214                 type ofs = (max+1)/2; \
215                 for( int y=0; y<h; ++y ) { \
216                         type *row = (type*)frame->get_rows()[y]; \
217                         for( int x=0; x<w; ++x ) { \
218                                 row[0] = row[0] * a; \
219                                 row[1] = (row[1]-ofs) * a + ofs; \
220                                 row[2] = (row[2]-ofs) * a + ofs; \
221                                 row += components; \
222                         } \
223                 } \
224         } \
225         else {\
226                 for( int y=0; y<h; ++y ) { \
227                         type *row = (type*)frame->get_rows()[y]; \
228                         for( int x=0; x<w; ++x ) { \
229                                 row[0] *= a; \
230                                 row[1] *= a; \
231                                 row[2] *= a; \
232                                 row += components; \
233                         } \
234                 } \
235         } \
236 } while(0)
237
238         float a = config.a;
239         switch( frame->get_color_model() ) {
240         case BC_RGB888:     MAIN_LOOP(uint8_t, 3, 0, 0xff);  break;
241         case BC_RGB_FLOAT:  MAIN_LOOP(float,   3, 0, 1.0 );  break;
242         case BC_YUV888:     MAIN_LOOP(uint8_t, 3, 1, 0xff);  break;
243         case BC_RGBA8888:   MAIN_LOOP(uint8_t, 4, 0, 0xff);  break;
244         case BC_RGBA_FLOAT: MAIN_LOOP(float,   4, 0, 1.0 );  break;
245         case BC_YUVA8888:   MAIN_LOOP(uint8_t, 4, 1, 0xff);  break;
246         }
247
248         return 0;
249 }
250
251
252 void AlphaMain::update_gui()
253 {
254         if( !thread ) return;
255         AlphaWindow *window = (AlphaWindow*)thread->window;
256         if( !window ) return;
257         if( !load_configuration() ) return;
258         window->lock_window("AlphaMain::update_gui");
259         window->update();
260         window->unlock_window();
261 }
262
263
264 void AlphaMain::save_data(KeyFrame *keyframe)
265 {
266         FileXML output;
267         output.set_shared_output(keyframe->xbuf);
268         output.tag.set_title("ALPHA");
269         output.tag.set_property("A", config.a);
270         output.append_tag();
271         output.terminate_string();
272 }
273
274 void AlphaMain::read_data(KeyFrame *keyframe)
275 {
276         FileXML input;
277         input.set_shared_input(keyframe->xbuf);
278
279         int result = 0;
280         while( !(result = input.read_tag()) ) {
281                 if( input.tag.title_is("ALPHA") ) {
282                         config.a = input.tag.get_property("A", config.a);
283                 }
284         }
285 }
286